Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 高級開發 >> Android:分析onXXX事件監聽器中的兩個參數position和id

Android:分析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代碼

  private class PerformClick extends WindowRunnnable implements Runnable {

  VIEw mChild;//子視圖

  int mClickMotionPosition;//單擊事件的所在位置(該位置應理解為某集合中的位置。)

  //執行主方法

  public void run() {

  if (mDataChanged) return;

  //這個是告知android我們用哪個場景來展示數據。

  //SimpleAdapter還是CursorAdapter?

  //闡述策略模式的一個真實場景。

  final ListAdapter adapter = mAdapter;

  //這個就是我們經常看到的position。

  final int motionPosition = mClickMotionPosition;

  if (adapter != null && mItemCount > 0 &&

  motionPosition != INVALID_POSITION &&

  motionPosition < adapter.getCount() && sameWindow()) {

  接上頁

  //positon還是原來的position,但id就不一樣了,它是依靠position來計算得出的值。

  //adapter getItemId(motionPosition)也說明了兩種場景下的實現方式也是不一樣的。

  performItemClick(mChild, motionPosition, adapter.getItemId(motionPosition));

  }

  }

  }

  private class PerformClick extends WindowRunnnable implements Runnable {

  VIEw mChild;//子視圖

  int mClickMotionPosition;//單擊事件的所在位置(該位置應理解為某集合中的位置。)

  //執行主方法

  public void run() {

  if (mDataChanged) return;

  //這個是告知android我們用哪個場景來展示數據。

  //SimpleAdapter還是CursorAdapter?

  //闡述策略模式的一個真實場景。

  final ListAdapter adapter = mAdapter;

  //這個就是我們經常看到的position。

  final int motionPosition = mClickMotionPosition;

  if (adapter != null && mItemCount > 0 &&

  motionPosition != INVALID_POSITION &&

  motionPosition < adapter.getCount() && sameWindow()) {

  //positon還是原來的position,但id就不一樣了,它是依靠position來計算得出的值。

  //adapter getItemId(motionPosition)也說明了兩種場景下的實現方式也是不一樣的。

  performItemClick(mChild, motionPosition, adapter.getItemId(motionPosition));

  }

  }

  }

  CursorAdapter場景中的id是怎樣實現的?

  Java代碼

  public long getItemId(int position) {

  if (mDataValid && mCursor != null) {

  //游標挪到了position的位置上。

  if (mCursor.moveToPosition(position)) {

  //參數mRowIDColumn就是主鍵ID位置,也就是上文所說的帶有”_id”的字段的位置。

  return mCursor.getLong(mRowIDColumn);

  } else {

  return 0;

  }

  } else {

  return 0;

  }

  }

  public long getItemId(int position) {

  接上頁

  if (mDataValid && mCursor != null) {

  //游標挪到了position的位置上。

  if (mCursor.moveToPosition(position)) {

  //參數mRowIDColumn就是主鍵ID位置,也就是上文所說的帶有”_id”的字段的位置。

  return mCursor.getLong(mRowIDColumn);

  } else {

  return 0;

  }

  } else {

  return 0;

  }

  }

  android.database.CursorWindow定義並實現了getLong(),參見下面源碼:

  Java代碼

  public long getLong(int row, int col) {

  acquireReference();

  try {

  // getLong_native是本地方法,底層計算得出視圖中我們單擊的那個實際行位置

  //參數col就是上面提到的那個mRowIDColumn。

  return getLong_native(row - mStartPos, col);

  } finally {

  releaseReference();

  }

  }

  public long getLong(int row, int col) {

  acquireReference();

  try {

  // getLong_native是本地方法,底層計算得出視圖中我們單擊的那個實際行位置

  //參數col就是上面提到的那個mRowIDColumn。

  return getLong_native(row - mStartPos, col);

  } finally {

  releaseReference();

  }

  }

  SimpleAdapter場景中的id是怎樣實現的?

  了解了CursorAdapter場景的id實現方式,那麼SimpleAdapter的實現方式就更容易了解了,非常簡單,參見下面源碼:

  Java代碼

  public long getItemId(int position) {

  //返回的就是position

  return position;

  }

  public long getItemId(int position) {

  //返回的就是position

  return position;

  }

  二、使用方式

  分兩種場景,以代碼的形式來展示使用方式,以下均選中第2行:

  1.SimpleAdapter

  Java代碼

  //模擬數據,其中_id類似於數據庫中的主鍵,主鍵名一定要帶有”_id”,android好這口。雖然不是從數據庫獲取的數據,但最好也要遵從這種習慣。

  接上頁

  ArrayList> classic = new ArrayList>();

  HashMap englishMap = new HashMap();

  englishMap.put(“classic_id”,1l);

  englishMap.put(“name”,lileilei);

  englishMap.put(“gender”,male);

  englishMap.put(“classic _id”,2l);

  englishMap.put(“name”,hanmeimei);

  englishMap.put(“gender”,female);

  englishMap.put(“classic _id”,3l);

  englishMap.put(“name”,poly);

  englishMap.put(“gender”,male);

  //創建SimpleAdater

  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 });

  //設置監聽器

  ListView lv = this.findViewById(R.id.listvIEw);

  lv.setAdapter(simpleAdapter);

  lv.setOnItemClickListener(new OnItemClickListener() {

  @Override

  public void onItemClick(AdapterView parent, View vIEw,

  int position, long id) {

  Log.i(LOG_TAG, "position:" + position);//輸出1

  Log.i(LOG_TAG, "id:" + id);//輸出1

  Log.i(LOG_TAG, "item class : "+ ((ListVIEw) parent).getItemAtPosition(position).getClass().getSimpleName());//輸出item class : HashMap

  //由於上面第三條日志信息輸出的類型為HashMap,所以采用HashMap的方式獲取數據。

  HashMap englishMap = (HashMap) ((ListVIEw) parent).getItemAtPosition(position);

  if (englishMap!= null && englishMap.size()> 0) {

  //做其他操作

  }

  }

  });

  //模擬數據,其中_id類似於數據庫中的主鍵,主鍵名一定要帶有”_id”,android好這口。雖然不是從數據庫獲取的數據,但最好也要遵從這種習慣。

  ArrayList> classic = new ArrayList>();

  HashMap englishMap = new HashMap();

  englishMap.put(“classic_id”,1l);

  englishMap.put(“name”,lileilei);

  englishMap.put(“gender”,male);

  接上頁

  englishMap.put(“classic _id”,2l);

  englishMap.put(“name”,hanmeimei);

  englishMap.put(“gender”,female);

  englishMap.put(“classic _id”,3l);

  englishMap.put(“name”,poly);

  englishMap.put(“gender”,male);

  //創建SimpleAdater

  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 });

  //設置監聽器

  ListView lv = this.findViewById(R.id.listvIEw);

  lv.setAdapter(simpleAdapter);

  lv.setOnItemClickListener(new OnItemClickListener() {

  @Override

  public void onItemClick(AdapterView parent, View vIEw,

  int position, long id) {

  Log.i(LOG_TAG, "position:" + position);//輸出1

  Log.i(LOG_TAG, "id:" + id);//輸出1

  Log.i(LOG_TAG, "item class : "+ ((ListVIEw) parent).getItemAtPosition(position).getClass().getSimpleName());//輸出item class : HashMap

  //由於上面第三條日志信息輸出的類型為HashMap,所以采用HashMap的方式獲取數據。

  HashMap englishMap = (HashMap) ((ListVIEw) parent).getItemAtPosition(position);

  if (englishMap!= null && englishMap.size()> 0) {

  //做其他操作

  }

  }

  });

  2. CursorAdapter

  Java代碼

  //從數據庫中獲取數據,同樣,返回的Cursor中必須含有”_id”的字段。

  Cursor cursor = .....;//寫一個查詢數據的方法並返回一個Cursor對象;

  //創建SimpleCursorAdapter

  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 });

  //設置監聽器

  ListView lv = this.findViewById(R.id.listvIEw);

  lv.setAdapter(simpleCursorAdapter);

  接上頁

  lv.setOnItemClickListener(newOnItemClickListener() {

  @Override

  public void onItemClick(AdapterView parent, View vIEw,int position, long id) {

  Log.i(LOG_TAG, "position:" + position);//輸出1

  Log.i(LOG_TAG, "id:" + id);//輸出2

  Log.i(LOG_TAG, "item class : "+ ((ListVIEw) parent).getItemAtPosition(position).getClass().getSimpleName());//輸出item class : SQLiteCursor

  //由於上面第三條日志信息輸出的類型為SQLiteCursor,所以采用Cursor的方式獲取數據。

  Cursor cursor = (Cursor) ((ListVIEw) parent).getItemAtPosition(position);

  if (cursor != null && cursor.moveToPosition(position)) {

  //做其他操作

  }

  }

  });

  //從數據庫中獲取數據,同樣,返回的Cursor中必須含有”_id”的字段。

  Cursor cursor = .....;//寫一個查詢數據的方法並返回一個Cursor對象;

  //創建SimpleCursorAdapter

  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 });

  //設置監聽器

  ListView lv = this.findViewById(R.id.listvIEw);

  lv.setAdapter(simpleCursorAdapter);

  lv.setOnItemClickListener(newOnItemClickListener() {

  @Override

  public void onItemClick(AdapterView parent, View vIEw,int position, long id) {

  Log.i(LOG_TAG, "position:" + position);//輸出1

  Log.i(LOG_TAG, "id:" + id);//輸出2

  Log.i(LOG_TAG, "item class : "+ ((ListVIEw) parent).getItemAtPosition(position).getClass().getSimpleName());//輸出item class : SQLiteCursor

  //由於上面第三條日志信息輸出的類型為SQLiteCursor,所以采用Cursor的方式獲取數據。

  Cursor cursor = (Cursor) ((ListVIEw) parent).getItemAtPosition(position);

  if (cursor != null && cursor.moveToPosition(position)) {

  接上頁

  //做其他操作

  }

  }

  });

  四、總結

  目前還是要重點使用positon為上策,更復合程序員的編程習慣(下標以0開始);而id存在一定的變數,也許還未領會其實際用途吧,並且不太理解為什麼id要是long類型的。

  onItemClickListener()中的position和id就是這樣實現的,那與之相類似的監聽器也是如此。畢竟監聽器是實際開發中經常用到的,所以弄懂細枝末節還是有必要的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved