2009-12-31 38 views
43

Tôi có Android ListActivity được hỗ trợ bởi cơ sở dữ liệu Cursor qua một SimpleCursorAdapter.Android SimpleCursorAdapter không cập nhật khi thay đổi cơ sở dữ liệu

Khi các mục được nhấp, một trường cờ trong hàng coresponding trong cơ sở dữ liệu được bật và chế độ xem trong danh sách cần được cập nhật.

Vấn đề là, khi quan điểm cho rằng được cập nhật sẽ tắt màn hình và được tái chế, giá trị cũ sẽ được hiển thị trên giao diện khi nó trả về vào xem. Điều tương tự cũng xảy ra khi danh sách thr được vẽ lại (thay đổi định hướng, v.v.).

Tôi sử dụng notifydatasetchanged() để làm mới bộ điều hợp con trỏ nhưng có vẻ như không hiệu quả.

Tôi nên cập nhật cơ sở dữ liệu như thế nào để con trỏ cũng được cập nhật?

Trả lời

89

Gọi requery() trên Cursor khi bạn thay đổi dữ liệu trong cơ sở dữ liệu mà bạn muốn thể hiện ở chỗ Cursor (hoặc những điều Cursor populates, giống như một ListView qua một CursorAdapter).

A Cursor giống như một con trỏ phía máy khách ODBC - nó chứa tất cả dữ liệu được biểu thị bằng kết quả truy vấn. Do đó, chỉ vì bạn thay đổi dữ liệu trong cơ sở dữ liệu, Cursor sẽ không biết về những thay đổi đó trừ khi bạn làm mới thông qua requery().


CẬP NHẬT: toàn bộ câu hỏi này và tập hợp các câu trả lời nên bị xóa do tuổi già, nhưng đó là dường như không thể. Bất cứ ai tìm kiếm câu trả lời Android nên nhớ rằng Android là một mục tiêu nhanh chóng di chuyển, và câu trả lời từ năm 2009 thường tồi tệ hơn là câu trả lời mới hơn.

Giải pháp hiện tại là lấy Cursor mới và sử dụng changeCursor() hoặc swapCursor() trên CursorAdapter để ảnh hưởng đến thay đổi dữ liệu.

+0

Vì vậy, những gì hiện notifydatachanged làm gì? – CodeFusionMobile

+11

Không có "notifydatachanged". Nếu bạn có nghĩa là notifyDataSetChanged() trên Adapter, đó là cách SimpleCursorAdapter nói với ListView rằng dữ liệu đã được thay đổi. Để trích dẫn từ tài liệu, "Thông báo cho Chế độ xem được đính kèm rằng dữ liệu cơ bản đã được thay đổi và nó sẽ tự làm mới". Tuy nhiên, vấn đề của bạn không phải là với Adapter nói cho ListView về sự thay đổi - vấn đề của bạn là Adapter không biết dữ liệu đã thay đổi. Gọi requery() là cách để giải quyết vấn đề đó với một CursorAdapter. – CommonsWare

+0

Điều đó có ý nghĩa ngay bây giờ. Tôi hiểu lầm luồng dữ liệu. – CodeFusionMobile

37

requery hiện không còn được dùng nữa. từ số documentation:

Phương pháp này không còn được dùng nữa. Không sử dụng tính năng này. Chỉ cần yêu cầu một con trỏ mới, vì vậy bạn có thể thực hiện điều này một cách không đồng bộ và cập nhật chế độ xem danh sách của bạn khi con trỏ mới quay lại.

sau khi có được con trỏ mới, người dùng có thể sử dụng adapter.changeCursor(cursor). điều này sẽ cập nhật chế độ xem.

+0

Cảm ơn bạn đã biết thông tin, tôi đã gặp sự cố trên Honeycomb liên quan đến cursor.requery(), có thể điều này nằm sau nó. – CodeFusionMobile

+0

Tình huống thường gặp là thay đổi giá trị từ onClickListener() Câu đố của tôi là một mặt, chúng tôi đang gửi con trỏ ban đầu thông qua hàm tạo (tức là truy vấn được viết bên ngoài Adpater) Nhưng mặt khác, onlickLister bị coi là lớp lồng nhau bên trong bộ điều hợp. Vì vậy, truy vấn cho con trỏ mới sẽ được viết bên trong lớp bộ điều hợp. Điều này có thể gây ra mã trùng lặp. Thiết kế phù hợp để viết truy vấn chỉ một lần trong mã nguồn là gì? –

20

Trong trường hợp sử dụng bộ nạp và con trỏ automagically tạo ra bạn có thể gọi:

getLoaderManager().restartLoader(0, null, this); 

trong hoạt động của bạn, chỉ cần sau khi thay đổi một cái gì đó trên một DB, tái sinh mới của con trỏ. Đừng quên cũng có xử lý sự kiện định nghĩa:

@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    CursorLoader cursorLoader = 
      new CursorLoader(this, 
        YOUR_URI, 
        YOUR_PROJECTION, null, null, null); 
    return cursorLoader; 
} 

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
    adapter.swapCursor(data); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
    adapter.swapCursor(null); 
} 
+2

Đó là một giải pháp tốt. Cảm ơn bạn vì câu trả lời này. – Vincent

+2

Đã thử một nửa tá những thứ khác nhau từ xung quanh Stack Overflow và đây là một trong những cuối cùng đã làm việc cho tôi. Cảm ơn bạn! – Rudism

+0

Đây chính xác là câu trả lời tôi đang tìm kiếm, sử dụng một bộ điều hợp đơn giản và gọi swapCursor onLoadFinished. – Matt

1

Tôi không rõ ràng nếu bạn đặt autoRequery tài sản của CursorAdapter để true.

Bộ điều hợp sẽ kiểm tra thuộc tính autoRequery; nếu nó là false thì con trỏ sẽ không bị thay đổi.

+0

'init void được bảo vệ (Ngữ cảnh bối cảnh, Cursor c, boolean autoRequery)' * Phương pháp này không được chấp nhận. Không sử dụng điều này, sử dụng hàm tạo thông thường. Điều này sẽ bị xóa trong tương lai. * – Mussa

0

requery() đã bị phản đối, chỉ cần thực hiện các phương pháp đơn giản updateUI() như thế này trong lớp con của CursorAdapter của bạn và gọi nó là sau khi cập nhật dữ liệu:

private void updateUI(){ 
    swapCursor(dbHelper.getCursor()); 
    notifyDataSetChanged(); 
} 
0

Thật dễ dàng.

private Db mDbAdapter; 
private Cursor mCursor; 
private SimpleCursorAdapter mCursorAd; 

..................................... 
//After removing the item from the DB, use this 
..................................... 

mCursor = mDbAdapter.getAllItems(); 
mCursorAd.swapCursor(mCursor); 

Hoặc sử dụng CursorLoader ...

Các vấn đề liên quan