你的位置:首页 > 操作系统

[操作系统]和SimpleCursorAdapter有关的小问题


今天学习sqlite的时候,用到了simpleCursorAdapter.SimpleCursorAdapter是Android专门为了连接数据库与视图而产生的。他是将从数据库表中获取的数据显示到ListView的桥梁。按照网上教程,我利用ListView体现SimpleCursorAdapter的用法。

1     ListView list=(ListView)findViewByID(R.id.listview);2     SQLiteDatabase dbread=db.getReadableDatabase();3     Cursor cur=dbread.query("user",null,null,null,null,null,null);4     adapter=new SimpleCursorAdapter(this,R.layout.layout,cur,new String[]{"name","sex"},new int[]{R.id.name,R.id.sex});5     listview.setAdapter(sca);

但是,调试的时候应用报错,column '_id' does not exist。然后才看到教程里写必须要求我们的数据库中有一列,_id;SimpleCursorAdapter非常傲娇, 如果没有这列,就不干了。

  还有两个问题,1.SimpleCursorAdapter 中间出现了一道横线,那说明这个函数已经过时,代替的函数是什么.2.当数据库数据更新时,使用adapter.notifyDataSetChanged(),列表并未更新,那么如何保证UI及时更新?

 找到的代替SimplecursorAdapter构造方法的函数是:SimpleCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to,int flags) 相较于之前的,仅仅多了一个 flags。flags在这里是用来标识当数据发生改变调用onContentChanged()的时候是否通知ContentProvider数据改变。对应有两个常数:CursorAdapter。FLAG_AUTO_REQUERY和CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER。前者在api11后不推荐使用,就不在叙述。后者的作用是在 Cursor 上注册一个内容监测器,并在其发出通知时调用 onContentChanged() 方法。

如果无需监听ContentProvider的改变,或者,在CursorAdapter中使用了CursorLoader(他会为你注册一个内容监测器),则可以传0。

在UI更新方面,我找到三个方法:

cursor.requery();adapter.notifyDataSetChanged();

 

adapter.swapCursor(newCursor);adapter.notifyDataSetChanged();

 

adapter.changeCursor(newCursor);adapter.notifyDataSetChanged();

 

第一种方法,requery被画上了横线,并且这个方法测试失败了。
第二种方法和第三种方法都成功了。查阅资料,swapCursor和changeCursor两种方法的区别介绍如下:

 

 1 public Cursor swapCursor(Cursor newCursor) { 2 if (newCursor == mCursor) { 3 return null; 4 } 5 Cursor oldCursor = mCursor; 6 if (oldCursor != null) { 7 if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver); 8 if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver); 9 }10 mCursor = newCursor;11 if (newCursor != null) {12 if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);13 if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);14 mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");15 mDataValid = true;16 // notify the observers about the new cursor17 notifyDataSetChanged();18 } else {19 mRowIDColumn = -1;20 mDataValid = false;21 // notify the observers about the lack of a data set22 notifyDataSetInvalidated();23 }24 return oldCursor;25 }

swapCursor 交换了一个新的 Cursor,返回旧的Cursor,它并未将旧Cursor关闭

 

1 public void changeCursor(Cursor cursor) {2     Cursor old = swapCursor(cursor);3     if (old != null) {4       old.close();5     }6   }

 


changeCursor则替换将原来的 Cursor关闭了。

如果使用了CursorLoader(这真是一个好东西),它会管理Cursor,不需要我们自己关闭Cursor,loader会完成。我们只需实现下面三种方法即可

 1 // Called when a new Loader needs to be created 2 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 3 // Now create and return a CursorLoader that will take care of 4 // creating a Cursor for the data being displayed. 5 return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, 6 PROJECTION, SELECTION, null, null); 7 } 8  9 // Called when a previously created loader has finished loading10 public void onLoadFinished(Loader<Cursor> loader, Cursor data) {11 // Swap the new cursor in. (The framework will take care of closing the12 // old cursor once we return.)13 mAdapter.swapCursor(data);14 }15 16 // Called when a previously created loader is reset, making the data unavailable17 public void onLoaderReset(Loader<Cursor> loader) {18 // This is called when the last Cursor provided to onLoadFinished()19 // above is about to be closed. We need to make sure we are no20 // longer using it.21 mAdapter.swapCursor(null);

 

参考资料:http://stackoverflow.com/questions/11093380/what-to-set-cursoradaptercontext-context-cursor-c-int-flags-to-in-order-to-m
http://www.blogc.at/2014/03/03/swapcursor-vs-changecursor-whats-the-difference/

http://developer.android.com/reference/android/widget/CursorAdapter.html#CursorAdapter(android.content.Context, android.database.Cursor, int)