ListView,CursorAdapter,ContextMenu之间的映射关系学习笔记。

这几天在学习NotePad的源码,对其中的ListView,CursorAdapter,ContextMenu数据之间的映射关系仔细研究了一下,在这记录一下。


在这先说一下SQLiteDatabase中的insert()这个方法的返回值为插入数据行的ID,具体在ContentProvider中的insert()方法中有引用:

	@Override
	public Uri insert(Uri uri, ContentValues initValues) {
		// TODO Auto-generated method stub
		if (uriMatcher.match(uri) != NOTES) {
			throw new IllegalArgumentException("Invalid uri" + uri);
		}
		ContentValues values;
		if (initValues != null) {
			values = new ContentValues(initValues);
		} else {
			values = new ContentValues();
		}

		long now = Long.valueOf(System.currentTimeMillis());

		if (values.containsKey(Notes.CREATED_DATE) == false) {
			values.put(Notes.CREATED_DATE, now);
		}
		if (values.containsKey(Notes.MODIFIED_DATE) == false) {
			values.put(Notes.MODIFIED_DATE, now);
		}
		if (values.containsKey(Notes.NOTE) == false) {
			values.put(Notes.NOTE, "");
		}
		if (values.containsKey(Notes.TITLE) == false) {
			values.put(Notes.TITLE,
					getContext().getResources().getString(R.string.untitle));
		}

		SQLiteDatabase db = myDBHelper.getWritableDatabase();
		long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
		Log.e(TAG, "from insert=>rowId:" + rowId);

		if (rowId > 0) {
			Uri noteUri = ContentUris.withAppendedId(Notes.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(noteUri, null);// 这个noteUri改成uri行吗,就是不带Id的那种,写完和实验一下
			return noteUri;
		}
		throw new SQLiteException("Insert Note Fail! uri=>" + uri);
	}
有上面的代码可以看到,在插入值的时候并没有指定Notes._ID的值,但是当你插入的时候会自动分配一个ID给属性Notes._ID列,默认的情况下,这个ID是自增的。

也就是会比当前最大的那个id+1(可能由于删除操作,删除前面的行,比如说一共有18行,1~18,删掉第一行,还剩2~18,再插入一行数据之后,数据的ID列在数据库中的

值是19);首先对这个ID的来源有所了解了,你会发现以后在查询的时候凡是用到映射的地方都会在映射中加入ID,因为在ListView中显示的Item的ID就是在数据库中ID列

的值,而不是在SimpleCursorAdapter的位置,SimpleCursorAdapter的位置对应的是ListView的从头到尾显示的顺序,现在说好像有点抽象,上图。


每个Item都会有一个ID,该ID对应的值也就是在数据库中Notes._ID对应的值,知道这个Notes._ID和ListView之间的关系了吧,

也就是ListView中的Item的ID对应的就是每行数据的ID列的值,这也就是为什么一般使用ContentProvider的时候都会用到ID这一列

的原因,因为这样设计才能根据你的点击映射到数据库的数据上面。

那么Item的显示顺序是由什么来决定的呢?

答案是有CusorAdapter中的位置决定。由于CursorAdapter是对Cursor的适配,而Cursor又是根据一定条件按照一定顺序从数据库中

筛选出来的,所以Cursor中数据的顺序也就是显示的顺序。这跟数据行的ID没有什么关系。上图:


在NotePad中使用的是根据modified这一列的降序排列,也就是根据修改时间排列的,谁最后修改的排在最前面,但是可能这个data0的ID由于是在insert创建决定的,(

比如是在data1,data2之后,那么他的ID = 3而在CursorAdapter中的position是2(起始点是0,1,2))。


好了说了这么多好像把基本的脉络差不多里清楚了,那么再来研究一下这个ContextMenu();所谓的ContextMenu简单来说就是你长按一个VIew之后弹出来的菜单,

不过前提是你要给这个组件注册一下listener,View.setOnCreateContextMenuListener(Listener);对应在Notepad中的代码是:

getListView().setOnCreateContextMenuListener(this);

当完成注册之后呢,如果每次长按ListView中的一个Item就会触发onCreateContextMenu()这个回调函数,Notepad中的代码:

@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo info) {
		AdapterContextMenuInfo menuinfo;
		try {
			menuinfo = (AdapterContextMenuInfo) info;
		} catch (ClassCastException e) {
			Log.e(TAG, "from onCreateContextMenu()");
			return;
		}
		Cursor cursor = (Cursor) getListAdapter().getItem(menuinfo.position);
		if (cursor == null) {
			Log.e(TAG, "cursor == null");
			return;
		}
		menu.setHeaderTitle(cursor.getString(TITLE_COLUME_INDEX));
		menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_delete);
	}

关键是这几个参数的理解,上官方文档~

Called when the context menu for this view is being built. It is not safe to hold onto the menu after this method returns.
Parameters
<span style="color:#CC0000;">menu </span>	The context menu that is being built
<span style="color:#CC0000;">v</span> 	The view for which the context menu is being built
<span style="color:#CC0000;">menuInfo</span> 	Extra information about the item for which the context menu should be shown. This information will vary depending on the class of v. 

menu也就是即将要创建的这个ContextMenu了;

v也就是你setOnCreateContextMenuListener()的View;

menuInfo就好呢有讲究了,详细说一下啊。

menuInfo的类型是ContextMenuInfo该类中有三个变量,上官方文档~

<span style="color:#CC0000;">public long id</span>
Added in API level 1

The row id of the item for which the context menu is being displayed.

<span style="color:#CC0000;"> public int position</span>
Added in API level 1

The position in the adapter for which the context menu is being displayed.

<span style="color:#CC0000;"> public View targetView</span>
Added in API level 1

The child view for which the context menu is being displayed. This will be one of the children of this AdapterView.
id也就是Item的ID也就是数据行的ID;

position也就是在CursorAdapter中的位置,也就是Item的显示顺序对应的位置;

targetView也不知道干啥的。我getId一直都是-1,看官方文档的意思就是AdapterView的child,所谓的AdapterView就是该View的Child是由Adapter来决定的,常见的

就是ListView,GridView,Spinner和Gallery;

上面在onCreateContextMenu()中用到了menuinfo.position也就是CursorAdapter中的位置,通过Adapter.getItem(menuinfo.position)或的该行的数据行保留在Cursor

中,然后在通过Cursor获取每列的值。


好像寒不够充分,在说一下,点击弹出来的ContextMenu的Item的处理函数,onContextItemSelected():

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		AdapterContextMenuInfo menuinfo;
		try {
			menuinfo = (AdapterContextMenuInfo) item.getMenuInfo();
		} catch (ClassCastException e) {
			Log.e(TAG, "from onContextItemSelected()");
			return false;
		}
		switch (item.getItemId()) {
		case MENU_ITEM_DELETE:
			Uri uri = ContentUris.withAppendedId(getIntent().getData(),
					menuinfo.id);
			getContentResolver().delete(uri, null, null);
			return true;
		}
		return false;
	}

这个函数中通过MenuInfo的id获得数据的Id,然后根据id删除相应的数据行。


说到这,相信也基本把ListView,SimpleCursorAdapter,ContextMenu三者的映射关系



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值