32

Tôi đang thiết lập ứng dụng của mình để mọi người có thể tạo nhóm bạn bè của họ. Khi một nhóm được tạo ra, nó ghi 2 bảng vào cơ sở dữ liệu SQL. Bảng đầu tiên có tên nhóm và id nhóm. Bảng thứ hai có 2 cột, một id nhóm và một id người dùng. Điều này làm việc tốt.Cách đọc DB SQLite trong android bằng trình tải con trỏ?

Tuy nhiên, bây giờ tôi muốn có thể đọc từ cơ sở dữ liệu. Tôi đang sử dụng phân đoạn listview với số cursorloader nhưng tôi đang gặp sự cố khi nhận thông tin để hiển thị. Tôi muốn liệt kê tất cả các tên nhóm từ bảng đầu tiên trong chế độ xem danh sách của tôi.

Vấn đề của tôi là khi lần đầu tiên tôi sử dụng cursorloader để liệt kê các liên hệ của mình, tôi đã sử dụng Uri từ content provider theo phương pháp onCreateLoader. Cụ thể tôi có CONTENT_URI từ lớp ContactsContracts.Contacts.

Ví dụ về cursorloader với contentprovider:

@Override 
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
    Uri contentUri = ContactsContract.Contacts.CONTENT_URI; 
    return new CursorLoader(getActivity(),contentUri,PROJECTION,SELECTION,ARGS,ORDER); 
} 

Tuy nhiên, không sử dụng một nhà cung cấp nội dung, tôi không biết những gì để đưa vào phương pháp onCreateLoaderreturn new CursorLoader(...) đòi hỏi một Uri trong đối số thứ hai.

Bất kỳ đề xuất nào về cách tôi có thể hiển thị dữ liệu cơ sở dữ liệu của mình trong chế độ xem danh sách?

đoạn mã lớp:

public class GroupListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { 

CursorAdapter mAdapter; 
private OnItemSelectedListener listener; 
private static final String[] PROJECTION ={GroupContract.GroupDetails.COLUMN_NAME_GROUP_NAME}; 
private static final String SELECTION = null; 
final String[] FROM = {GroupContract.GroupDetails.COLUMN_NAME_GROUP_NAME}; 
final int[] TO = {android.R.id.text1}; 
private static final String[] ARGS = null; 
private static final String ORDER = null; 
private Cursor c; 


@Override 
public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1,null,FROM,TO,0); 
    ReadDBAsync readDB = new ReadDBAsync(); 
    readDB.execute(); 
} 

@Override 
public void onActivityCreated(Bundle savedInstanceState){ 
    super.onActivityCreated(savedInstanceState); 
    setListAdapter(mAdapter); 
    getLoaderManager().initLoader(0,null,this); 
} 

@Override 
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
    Uri contenturi = Uri.parse("content://preamble.oneapp"); 
    Uri tableuri = Uri.withAppendedPath(contenturi,GroupContract.GroupDetails.TABLE_NAME); 
    return new CursorLoader(getActivity(),tableuri,PROJECTION,SELECTION,ARGS,ORDER); 
} 

@Override 
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 
    mAdapter.swapCursor(cursor); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> cursorLoader) { 
    mAdapter.swapCursor(null); 
} 


private class ReadDBAsync extends AsyncTask<Void,Void,String> { 

    @Override 
    protected String doInBackground(Void... voids) { 

     ContractDBHelpers mDBHelper = new ContractDBHelpers(getActivity()); 
     SQLiteDatabase db = mDBHelper.getReadableDatabase(); 
     String returnvalue = "database read"; 
     c = db.query(GroupContract.GroupDetails.TABLE_NAME,PROJECTION,null,null,null,null,null); 
     return returnvalue; 
    } 

    @Override 
    protected void onPostExecute(String result){ 
     Toast.makeText(getActivity(), result, Toast.LENGTH_LONG).show(); 
    } 
} 

} 
+0

Bạn đã tạo nhà cung cấp nội dung để quản lý cơ sở dữ liệu của mình? – user936414

+0

@ user936414 không, có cần thiết không? những lợi ích/bất lợi khi làm như vậy là gì? Chỉnh sửa: chỉ cần đọc lên trên nó, tôi không cần phải chia sẻ dữ liệu trên nhiều ứng dụng vì vậy tôi không cần một nhà cung cấp nội dung –

Trả lời

35

Đây là các bước để tạo một cursorloader trong một đoạn danh sách

1) Tạo một lớp mở rộng SQLiteOpenHelper và ghi đè onCreateonUpgrade để tạo bảng của bạn.

2) Tạo lớp mở rộng ContentProvider và tạo URI để truy cập cơ sở dữ liệu của bạn. Tham khảo http://developer.android.com/guide/topics/providers/content-providers.html. Thêm URI của bạn vào số URIMatcher mà bạn sử dụng trong onCreate, onUpdate, truy vấn, v.v. (phương pháp ghi đè) để khớp với URI. Tham khảo http://developer.android.com/reference/android/content/UriMatcher.html

3) Trong phương thức chèn, hãy gọi getContext().getContentResolver().notifyChange(uri, null). Trong phương thức truy vấn, hãy gọi setNotificationUri(ContentResolver cr, Uri uri) trước khi trả lại nhà cung cấp nội dung để thay đổi chèn để phản ánh tự động cho trình tải của bạn. (https://stackoverflow.com/a/7915117/936414).

4) Cung cấp URI đó trong onCreateLoader.

Lưu ý: Nếu không có nhà cung cấp nội dung, việc làm mới tự động các thay đổi đối với danh sách sẽ không khả thi như phiên bản Android hiện tại. Nếu bạn không muốn trình hiển thị nội dung của mình hiển thị, hãy đặt thuộc tính đã xuất trong tệp kê khai thành sai. Hoặc bạn có thể triển khai CursorLoader tùy chỉnh của mình như trong https://stackoverflow.com/a/7422343/936414 để truy xuất dữ liệu từ cơ sở dữ liệu. Nhưng trong trường hợp này, không thể tự động làm mới dữ liệu

+9

cảm ơn thông tin của bạn tôi sẽ xem xét nó. Tôi thấy kỳ lạ là các tùy chọn của tôi là sử dụng 'ContentProvider' (mà tôi không cần) hoặc tạo tùy chỉnh' CursorLoader' của riêng tôi (có vẻ là công việc bổ sung) ... Sẽ không truy vấn cơ sở dữ liệu mà không có 'nhà cung cấp nội dung' đủ phổ biến để họ có thể thực hiện điều này mà không cần thực hiện thêm công việc? –

+0

Một trong những lý do có contentprovider là họ có thể thông báo cho tất cả các Nhà quan sát đã đăng ký (đã đăng ký trong CursorLoader) khi nội dung trong cơ sở dữ liệu thay đổi. – user936414

+5

Nếu loại dữ liệu này không thay đổi thì sao? Tôi cũng thấy rất kỳ quặc khi bị buộc phải sử dụng một 'ContentProvider'. Không có giải pháp nhanh hơn/nhẹ hơn cho dữ liệu sqlite tĩnh? –

62

Hướng dẫn Android đề xuất tạo ContentProvider khi bạn muốn chia sẻ dữ liệu của mình với các ứng dụng khác. Nếu bạn không cần điều này, bạn chỉ có thể ghi đè phương thức loadInBackgroud() của lớp CursorLoader. Ví dụ: viết như thế này trong số onCreateLoader:

return new CursorLoader(YourContext, null, YourProjection, YourSelection, YourSelectionArgs, YourOrder) 
      { 
       @Override 
       public Cursor loadInBackground() 
       { 
        // You better know how to get your database. 
        SQLiteDatabase DB = getReadableDatabase(); 
        // You can use any query that returns a cursor. 
        return DB.query(YourTableName, getProjection(), getSelection(), getSelectionArgs(), null, null, getSortOrder(), null); 
       } 
      }; 
+12

Đây là những gì tôi sử dụng vì tôi không cần phải chia sẻ dữ liệu của mình và tôi không muốn cấu trúc lại API cơ sở dữ liệu của mình thành ContentProvider. Nhược điểm là không có ContentProvider, listviews của tôi không tự động biết khi nào dữ liệu đã thay đổi, đó là một trong những điều tốt đẹp về ContentProviders. Để có được xung quanh mà tôi tạo lại bộ tải của tôi khi tôi biết một thay đổi đã được thực hiện, tức là thay vì gọi 'Cursor.requery()' Bây giờ tôi sử dụng 'getLoaderManager(). RestartLoader (MY_LOADER_ID, null, this);'. Điều này là khó xử, nhưng đó là cách đơn giản nhất mà tôi đã tìm thấy để thay thế phương thức 'startManagingCursor()'. – Fish

+0

@Fish, Cảm ơn thông tin này, nhưng những gì tôi quan tâm biết bây giờ là ** đắt tiền 'restartLoader()' có thể là ..? ** Điều đó quan trọng phải không? – eRaisedToX

+0

Bất kỳ lý do nào tôi không nên trả lại AsyncTaskLoader nếu tôi không quan tâm đến việc chỉ định YourProjection, YourSelection, YourSelectionArgs và YourOrder? – steamer25

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