您的位置:首页 > 移动开发 > Android开发

android适配器SimpleCursorAdapter的使用以及最后一个参数的作用

2016-01-28 18:44 771 查看
在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及以上的版本中,已经被废弃了,是不建议使用的,我们还是来说明下使用方法

[code]        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对象的,在这个方法中

[code]@Deprecated
public 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方法

[code]    @Deprecated
    public void startManagingCursor(Cursor c) {
        synchronized (mManagedCursors) {
            mManagedCursors.add(new ManagedCursor(c));
        }
    }


以Cursor构建了一个ManagedCursor对象,并加入到一个类型为ArrayList的mManagedCursors容器里面去了,在Activity中的onDestroy()方法中,我们看到下面的代码

[code]        // 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()方法,我们看到如下代码

[code]            synchronized (mManagedCursors) {
                final int N = mManagedCursors.size();
                for (int i=0; i<N; 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来加载数据了

[code]        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);


在回调方法中写上对应的代码

[code]    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(this, Persons.CONTENT_URI, null, null, null, null);
    }

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

    @Override
    public void onLoaderReset(Loader<Cursor> 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 是个日本人写的,大家可以参照着看,我的部分代码也是来自于它
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: