android适配器SimpleCursorAdapter的使用以及最后一个参数的作用
在android开发中,我们经常用SimpleCursorAdapter来绑定数据库里面的数据,很多人在使用这个类的时候并不知道具体怎么样来用,或者说还有很多疑问,比如最后一个参数该怎么写,这个cursor什么时候关闭,是怎么管理cursor的等等。
在android的不同的版本中,对SimpleCursorAdapter的使用方法是不同的,我们先来看下SimpleCursorAdapter构造方法,SimpleCursorAdapter有两个构造方法,其实可以归并为一个构造方法,我们看下构造方法的说明:
我们看最后一个参数flags,它有两个值可以选择分别为:CursorAdapter.FLAG_AUTO_REQUERY
和CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
,另外一个构造方法就是少了最后一个参数,默认被设置为CursorAdapter.FLAG_AUTO_REQUERY
。
首先我们来看没有flag参数或者参数为CursorAdapter.FLAG_AUTO_REQUERY
的情况,这种是在android3.0以下版本中才使用的,在分为android3.0及以上的版本中,已经被废弃了,是不建议使用的,我们还是来说明下使用方法
final Cursor c = managedQuery(Persons.CONTENT_URI, null, null, null, null); SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter( this, R.layout.list_item, c, new String[] {Persons.NAME, Persons.AGE}, new int[] {R.id.textViewName, R.id.textViewAge} ); ListView listView = (ListView)findViewById(R.id.listView); listView.setAdapter(simpleCursorAdapter);
正如字面意思,FLAG_AUTO_REQUERY会自动查询如果数据库中的数据发生了变化以实时反映到界面上来,这样使用有一个问题,查询数据是发生在UI线程中,会造成卡顿的现象,甚至出现ANR异常,取决于手机的配置及数据的大小,这也是android3.0及以上放弃的原因,尽管如此,我们还是有些问题需要来理解。
一般来说我们使用Cursor需要close,但是在这里我们并没close,那么是怎么处理的呢,原理是Activity自己帮我处理的,大家看我是使用managedQuery来获取Cursor对象的,在这个方法中
@Deprecatedpublic final Cursor managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (c != null) { startManagingCursor(c); } return c;}
用getContentResolver().query()获取到Cursor对象以后,使用startManagingCursor()把Cursor对象加入到Activity中管理。我们看下startManagingCursor方法
@Deprecated public void startManagingCursor(Cursor c) { synchronized (mManagedCursors) { mManagedCursors.add(new ManagedCursor(c)); } }
以Cursor构建了一个ManagedCursor对象,并加入到一个类型为ArrayList的mManagedCursors容器里面去了,在Activity中的onDestroy()方法中,我们看到下面的代码
// close any cursors we are managing. synchronized (mManagedCursors) { int numCursors = mManagedCursors.size(); for (int i = 0; i < numCursors; i++) { ManagedCursor c = mManagedCursors.get(i); if (c != null) { c.mCursor.close(); } } mManagedCursors.clear(); }
没错,从mManagedCursors循环取出所有的ManagedCursor对象,并关闭里面的Cursor,在Activity中的performRestart()方法,我们看到如下代码
synchronized (mManagedCursors) { final int N = mManagedCursors.size(); for (int i=0; i ManagedCursor mc = mManagedCursors.get(i); if (mc.mReleased || mc.mUpdated) { if (!mc.mCursor.requery()) { if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { throw new IllegalStateException( "trying to requery an already closed cursor " + mc.mCursor); } } mc.mReleased = false; mc.mUpdated = false; } } }
我们看到了mCursor.requery()方法,这个方法是用来重新查询数据,在Activity重新开始的时候,performRestart()方法是Activity重新开始过程会被调用的方法。这下大家明白Activity是怎么管理Cursor的吧!注意如果大家在使用这个的时候一定要managedQuery()方法来获取Cursor,不然Cursor没被Activity管理,会游离在外,有可能会出现游标未关闭异常,大家最好不用这种方法了,android已经废弃!!!
然后我们看使用第二个参数来构建SimpleCursorAdapter对象即Flag为CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER,这是android3.0及以上的做法,我们需要使用到CursorLoader来加载数据了
simpleCursorAdapter = new SimpleCursorAdapter( this, R.layout.list_item, null, new String[] {Persons.NAME, Persons.AGE}, new int[] {R.id.textViewName, R.id.textViewAge}, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER ); ListView listView = (ListView)findViewById(R.id.listView); listView.setAdapter(simpleCursorAdapter); LoaderManager loaderManager = getLoaderManager(); loaderManager.initLoader(0, null, this);
在回调方法中写上对应的代码
@Override public Loader onCreateLoader(int id, Bundle args) { return new CursorLoader(this, Persons.CONTENT_URI, null, null, null, null); } @Override public void onLoadFinished(Loader loader, Cursor c) { simpleCursorAdapter.swapCursor(c); } @Override public void onLoaderReset(Loader loader) { simpleCursorAdapter.swapCursor(null); }
当数据库的数据变化的时候会自动回调onLoadFinished()来更新界面,同样这个方式也是由Activity来管理Cursor的,simpleCursorAdapter.swapCursor()会把之前的Cursor给close掉,并使用新的Cursor对象,onLoaderReset()就是由Activity中的performDestroy()来间接调用的,simpleCursorAdapter.swapCursor(null);被调用后就关闭了Cursor,这个方式获取Cursor是在子线程中,加载完成后会回调onLoadFinished()方法,不会阻塞UI线程,提高了流畅度,另外当Configuration发生变化是可以重用Cursor,不需要去重新获取Cursor,提高了效率,强烈的推荐大家在今后的开发中,使用这种方式。
好了,SimpleCursorAdapter的使用就说到这里,大家有什么疑问或者建议请给我留言!!!
最后给出一个参考demo https://github.com/takeyuweb/android-CursorLoaderSample 是个日本人写的,大家可以参照着看,我的部分代码也是来自于它
更多相关文章
- Android(安卓)HandlerThread用法
- 详解Android轻量型数据库SQLite
- Android(安卓)自定义RecyclerView.OnScrollListener,实现上拉分页
- android中的surface原理
- 获取web服务器xml数据
- Android(安卓)Data Binding 技术
- Android(安卓)Studio单元测试
- Android(安卓)NDK学习笔记3-入门案例篇
- android发现之旅之ViewRootImpl,Activity,Window,DecorView之间