編輯:高級開發
這就造成了一種困惑,我們在實際開發中,到底怎麼去理解去這兩個參數?我們又該怎麼去使用?兩者又何區別?
下面以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就是這樣實現的,那與之相類似的監聽器也是如此。畢竟監聽器是實際開發中經常用到的,所以弄懂細枝末節還是有必要的。
一般是一些被軟件工程師用於為特定的軟件包、軟件框架、硬件平台、操作系統等建立應用軟件的開發工具的集合,這種android SDK 安全性有助於減少惡意應用程序損害設備的
用戶卻不會喜愛它們。在移動應用中,簡潔明快才是用戶希望看到的。試想一下,當用戶在手機上玩一個RPG游戲,並被華麗的3D效果充斥了整個界面,那麼他將完全無法著手進行下一個
最近,關於Adobe在android平台上動作頻頻。昨天我們報道了Android版Flash 10.1發布 全面支持android 2.2的消息,今天又有消息稱,Ado
國外一家名為Phandroid的網站近日披露了android 3.0(Gingerbread)的一些細節。雖然新的系統仍在開發之中,不過我們仍然可以從曝光的一些細節中看