分析onXXX事件监听器中的两个参数position和id

 Android API中有部分事件监听器的方法中都会有参数position和id,它们是用来描述一个视图当中的某一项(item,当然你也可以理解成其它的意思)的属性。position描述该项在视图中所处的位置;而id描述的是该项的id,确切点说是该项在视图中所在的行位置。 
        这就造成了一种困惑,我们在实际开发中,到底怎么去理解去这两个参数?我们又该怎么去使用?两者又何区别? 
        下面以ListView中的onItemClickListener事件监听器为例,分析一下两者的区别及其如何使用。 
一、区别  
        貌似有点复杂,分两种场景来讨论: 
         1.ListView用SimpleAdapter展示数据  
        position:表示该项在视图中的位置,起始为0。 
        id:同上。 
         2.ListView用CursorAdapter展示数据  
        position: 同上。 
        id:表示该项在视图中实际位置,说白了就是起始为1。在视图上是第几行,就是第几行。举例:某个ListView共有5行数据,我选中了第3行,那么onItemClickListener()中的id就为3。 
         3.源码分析  
        上面简短的总结了两种场景下的含义,说再多也顶不上来自源码的分析: 
        同样也分两种场景,我们先来分析CursorAdapter场景: 
         是谁给参数position和id赋的值?  
        android.widget.AbsListView里面定义了一个私有内部类,用来处理ListView单击事件,参见下面源码: 
Java代码   收藏代码
  1. private class PerformClick extends WindowRunnnable implements Runnable {  
  2.         View mChild;//子视图  
  3.         int mClickMotionPosition;//单击事件的所在位置(该位置应理解为某集合中的位置。)  
  4.         //执行主方法  
  5.         public void run() {  
  6.             if (mDataChanged) return;  
  7.             //这个是告知Android我们用哪个场景来展示数据。  
  8.             //SimpleAdapter还是CursorAdapter?  
  9.             //阐述策略模式的一个真实场景。  
  10.             final ListAdapter adapter = mAdapter;  
  11.             //这个就是我们经常看到的position。  
  12.             final int motionPosition = mClickMotionPosition;  
  13.             if (adapter != null && mItemCount > 0 &&  
  14.                 motionPosition != INVALID_POSITION &&  
  15.                 motionPosition < adapter.getCount() && sameWindow()) {  
  16.                //positon还是原来的position,但id就不一样了,它是依靠position来计算得出的值。  
  17.                //adapter getItemId(motionPosition)也说明了两种场景下的实现方式也是不一样的。  
  18.                performItemClick(mChild, motionPosition, adapter.getItemId(motionPosition));  
  19.             }  
  20.         }  
  21.     }  

CursorAdapter场景中的id是怎样实现的?  
Java代码   收藏代码
  1. public long getItemId(int position) {  
  2.         if (mDataValid && mCursor != null) {  
  3.             //游标挪到了position的位置上。  
  4.             if (mCursor.moveToPosition(position)) {  
  5.                 //参数mRowIDColumn就是主键ID位置,也就是上文所说的带有”_id”的字段的位置。  
  6.                 return mCursor.getLong(mRowIDColumn);  
  7.             } else {  
  8.                 return 0;  
  9.             }  
  10.         } else {  
  11.             return 0;  
  12.         }  
  13.  }  

        android.database.CursorWindow定义并实现了getLong(),参见下面源码: 
Java代码   收藏代码
  1. public long getLong(int row, int col) {  
  2.         acquireReference();  
  3.         try {  
  4.             // getLong_native是本地方法,底层计算得出视图中我们单击的那个实际行位置  
  5.             //参数col就是上面提到的那个mRowIDColumn。  
  6.             return getLong_native(row - mStartPos, col);  
  7.         } finally {  
  8.             releaseReference();  
  9.         }  
  10.     }  

SimpleAdapter场景中的id是怎样实现的?  
        了解了CursorAdapter场景的id实现方式,那么SimpleAdapter的实现方式就更容易了解了,非常简单,参见下面源码: 
Java代码   收藏代码
  1. public long getItemId(int position) {  
  2.     //返回的就是position      
  3.     return position;  
  4. }  

二、使用方式  
        分两种场景,以代码的形式来展示使用方式,以下均选中第2行: 
         1.SimpleAdapter  
Java代码   收藏代码
  1. //模拟数据,其中_id类似于数据库中的主键,主键名一定要带有”_id”,Android好这口。虽然不是从数据库获取的数据,但最好也要遵从这种习惯。  
  2. ArrayList<HashMap<String, String>> classic = new ArrayList<HashMap<String, String>>();  
  3. HashMap<String, String> englishMap = new HashMap<String, String>();  
  4. englishMap.put(“classic_id”,1l);  
  5. englishMap.put(“name”,lileilei);  
  6. englishMap.put(“gender”,male);  
  7. englishMap.put(“classic _id”,2l);  
  8. englishMap.put(“name”,hanmeimei);  
  9. englishMap.put(“gender”,female);  
  10. englishMap.put(“classic _id”,3l);  
  11. englishMap.put(“name”,poly);  
  12. englishMap.put(“gender”,male);  
  13.   
  14. //创建SimpleAdater  
  15. SimpleAdapter simpleAdapter = new SimpleAdapter(this, data, R.layout.classic,new String[] { " classic _id""name""age" }, new int[] {R.id.id_text, R.id.name_text, R.id.age_text });  
  16.   
  17. //设置监听器  
  18. ListView lv = this.findViewById(R.id.listview);  
  19. lv.setAdapter(simpleAdapter);  
  20. lv.setOnItemClickListener(new OnItemClickListener() {  
  21.     @Override  
  22.     public void onItemClick(AdapterView<?> parent, View view,  
  23.         int position, long id) {  
  24.         Log.i(LOG_TAG, "position:" + position);//输出1  
  25.         Log.i(LOG_TAG, "id:" + id);//输出1  
  26.         Log.i(LOG_TAG, "item class : "+ ((ListView) parent).getItemAtPosition(position).getClass().getSimpleName());//输出item class : HashMap  
  27.       
  28.         //由于上面第三条日志信息输出的类型为HashMap,所以采用HashMap的方式获取数据。  
  29.        HashMap<String, String>  englishMap = (HashMap<String, String>) ((ListView) parent).getItemAtPosition(position);  
  30.        if (englishMap!= null && englishMap.size()> 0) {  
  31.              //做其他操作  
  32.        }  
  33.     }  
  34. });  


2. CursorAdapter  
Java代码   收藏代码
  1. //从数据库中获取数据,同样,返回的Cursor中必须含有”_id”的字段。  
  2. Cursor cursor = .....;//写一个查询数据的方法并返回一个Cursor对象;  
  3. //创建SimpleCursorAdapter  
  4. SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(this,R.layout.person, cursor, new String[] { " classic _id ""name""age" },new int[] { R.id.id_text, R.id.name_text, R.id.age_text });  
  5.   
  6. //设置监听器  
  7. ListView lv = this.findViewById(R.id.listview);  
  8. lv.setAdapter(simpleCursorAdapter);  
  9. lv.setOnItemClickListener(newOnItemClickListener() {  
  10.     @Override  
  11.     public void onItemClick(AdapterView<?> parent, View view,int position, long id) {  
  12.         Log.i(LOG_TAG, "position:" + position);//输出1  
  13.         Log.i(LOG_TAG, "id:" + id);//输出2  
  14.         Log.i(LOG_TAG, "item class : "+ ((ListView) parent).getItemAtPosition(position).getClass().getSimpleName());//输出item class : SQLiteCursor  
  15.       
  16.         //由于上面第三条日志信息输出的类型为SQLiteCursor,所以采用Cursor的方式获取数据。  
  17.        Cursor cursor = (Cursor) ((ListView) parent).getItemAtPosition(position);  
  18.        if (cursor != null && cursor.moveToPosition(position)) {  
  19.               //做其他操作  
  20.        }  
  21.     }  
  22. });  


四、总结  
        目前还是要重点使用positon为上策,更复合程序员的编程习惯(下标以0开始);而id存在一定的变数,也许还未领会其实际用途吧,并且不太理解为什么id要是long类型的。 
        onItemClickListener()中的position和id就是这样实现的,那与之相类似的监听器也是如此。毕竟监听器是实际开发中经常用到的,所以弄懂细枝末节还是有必要的。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值