32

我正在设置我的应用程序,以便人们可以创建他们的朋友组。创建组时,它将2个表写入SQL数据库。第一个表格有一个组名和一个组ID。第二个表格有2列,一个组ID和一个用户ID。这工作正常。如何使用cursorloader在android中读取SQLite数据库?

但是,现在我想能够从数据库中读取。我正在使用一个带有cursorloader的listview片段,但我无法获取要显示的信息。我想在列表视图中列出第一个表中的所有组名。

我的问题是,当我第一次在onCreateLoader方法所使用的cursorloader列出我的联系人,我使用的是Uricontent provider。具体来说,我从ContactsContracts.Contacts类有CONTENT_URI

cursorloadercontentprovider举例:

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

然而,如果没有使用内容提供商,我不知道要放什么东西在onCreateLoader方法,因为return new CursorLoader(...)需要在第二个参数中Uri

如何,我也许可以在列表视图中显示我的数据库中的数据什么建议吗?

片段类代码:

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

你是否创建了一个内容提供者来管理你的数据库? – user936414

+0

@ user936414不,这是必要的吗?这样做的好处/坏处是什么?编辑:只需阅读它,我不需要跨多个应用程序共享数据,所以我不需要一个内容提供商 –

回答

35

这些都是建立在一个列表片段

1)cursorloader的步骤创建扩展SQLiteOpenHelper一个类并重写onCreateonUpgrade来创建表。

2)创建扩展ContentProvider类,并创建访问数据库中的URI。请参阅http://developer.android.com/guide/topics/providers/content-providers.html。将您的URI添加到您在onCreate,onUpdate,查询等(重写方法)中使用的URIMatcher以匹配URI。参阅http://developer.android.com/reference/android/content/UriMatcher.html

3)在插入方法调用getContext().getContentResolver().notifyChange(uri, null)。在返回插入更改的内容提供者之前,查询方法调用setNotificationUri(ContentResolver cr, Uri uri)将自动反映到加载器。 (https://stackoverflow.com/a/7915117/936414)。

4)给出该URI在onCreateLoader

注: 没有一个内容提供商,更改列表的自动刷新是不作为目前Android版本是可行的。如果您不想让contentprovider可见,请将manifest中的导出属性设置为false。或者您可以实现您的自定义CursorLoader,如https://stackoverflow.com/a/7422343/936414从数据库检索数据。但在这种情况下,数据的自动刷新是不可能

+9

感谢您的信息,我会研究它。我觉得奇怪的是,我的选择是使用ContentProvider(我不需要它)或者创建自己的自定义的'CursorLoader'(这似乎是额外的工作)...不会查询数据库没有“内容提供者”是否足够普遍,以至于他们已经可以做到这一点,而不需要做额外的工作? –

+0

拥有内容提供者的原因之一是,当数据库中的内容发生变化时,他们可以通知所有注册的观察者(在CursorLoader中注册)。 – user936414

+5

如果这是一种不会改变的数据类型呢?我也觉得被迫使用一个'ContentProvider'非常奇怪。对于静态sqlite数据没有更快/更轻的解决方案吗? –

62

Android的指南建议创建一个ContentProvider时要与其他应用程序共享数据。如果你不需要这个,你可以覆盖CursorLoader类的方法loadInBackgroud()。例如,在你的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

这就是我使用的原因,因为我不需要共享我的数据,而且我不想将我的数据库API重构为ContentProvider。缺点是没有ContentProvider的东西,我的列表视图不会自动知道数据何时更改,这是ContentProviders的好处之一。为了解决这个问题,当我知道已经做出更改时,我重新创建了我的装载器,而不是调用'Cursor.requery()',现在使用'getLoaderManager()。restartLoader(MY_LOADER_ID,null,this);'。这很尴尬,但它是我找到的替代'startManagingCursor()'方法的最简单的方法。 – Fish

+0

@Fish,感谢这个信息,但是我现在知道的是**多么昂贵'restartLoader()'可以是..?**这很重要吗? – eRaisedToX

+0

如果我不在乎指定YourProjection,YourSelection,YourSelectionArgs和YourOrder,我不应该返回一个AsyncTaskLoader? – steamer25

相关问题