ListView 的position和id的區別


我們在使用ListView的時候,一般都會為ListView添加一個響應事件android.widget.AdapterView.OnItemClickListener。本文主要在於對OnItemClickListener的position和id參數做詳細的解釋,我相信有些人在這上面走了些彎路。

 

先來看一下官方的文檔
position The position of the view in the adapter.
id The row id of the item that was clicked.
而這兩行字並沒有解釋清楚 position和id的區別。另外,我們還有個Adapter的getView方法。

public abstract View getView (int positionView convertView, ViewGroup parent)

這里也有一個 position
 
初步接觸ListView的同學,一般會直接繼承ArrayAdapter,然后(比如我),就想當然的認為OnItemClick的 position和getView的 position是一樣的啊。於是我們就getItem( position)來獲取相應的數據。
 
那么這段代碼有沒有錯呢?如果有錯的話,在什么情況會出錯呢?
第一個問題的答案是,當我們為ListView添加headerView或者 footerView之后,這段代碼就不一定是我們想要的了。
 
出現問題的原因在於,當我們為ListView添加headerView或者 footerView之后,ListView在setAdapter時,做了一些事情,這導致,Adapter和OnItemClickListener中的 position含義發生了變化。

 

 

我們可以來看看ListView中setAdapter的實現

 

 public void setAdapter(ListAdapter adapter) {
      if (mAdapter != null && mDataSetObserver != null) {
          mAdapter.unregisterDataSetObserver(mDataSetObserver);
      }
      resetList();
      mRecycler.clear();
      if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
          mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
      } else {
          mAdapter = adapter;
      }
可以看出,如果這個ListView存在headerView或者 footerView的話,那么會在我們傳入的adapter外面在封裝一層HeaderViewListAdapter,這是一個專門用來自動處理headerView和 footerView的adapter。在ListView中,本身不區分headerView, footerView。ListView可以理解成是只負責管理一組View的數組的UI(ViewGroup),headerView和 footerView都委托給HeaderViewListAdapter來處理。(從這里也可以看到為什么API文檔中提到,addFooterView和addHeaderView要在setAdapter函數之前調用,如果在之后調用,那么就不會生成HeaderViewListAdapter,從而導致顯示不出headerView和 footerView)。
 
回到開頭的問題, position和id有啥區別。為此,我們找一下 position和id是怎么傳進來的。
OnItemClickListener在android.widget.AdapterView的 public boolean performItemClick(View view, int position, long id)函數中被調用。
performItemClick在 android.widget.AbsListView.PerformClick.run() 中被調用
  private class PerformClick extends WindowRunnnable implements Runnable {
      int mClickMotionPosition;
      public void run() {
          // The data has changed since we posted this action in the event queue,
          // bail out before bad things happen
          if (mDataChanged) return;
          final ListAdapter adapter = mAdapter;
          final int motionPosition = mClickMotionPosition;
          if (adapter != null && mItemCount > 0 &&
                  motionPosition != INVALID_POSITION &&
                  motionPosition < adapter.getCount() && sameWindow()) {
              final View view = getChildAt(motionPosition - mFirstPosition);
              // If there is no view, something bad happened (the view scrolled off the
              // screen, etc.) and we should cancel the click
              if (view != null) {
                  performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
              }
          }
      }
  }
可以看到, position事實上就是ListView中被點擊的view的位置。注意,在ListView中是不負責處理headerView和footViewer的,所以,這個位置應該是這個被點擊的view在數組[所有的headerView,用戶添加的view,所有的 footerView]中的位置(請自行參考HeaderViewListAdapter的getView實現)。而id是來自於adapter.getItemId( position)。
 
對於ArrayAdapter的getItemId函數,實現就是return  position。id和 position是一致的。
然而,對於HeaderViewListAdapter

 

public long getItemId(int position) {
      int numHeaders = getHeadersCount();
      if (mAdapter != null && position >= numHeaders) {
          int adjPosition = position - numHeaders;
          int adapterCount = mAdapter.getCount();
          if (adjPosition < adapterCount) {
              return mAdapter.getItemId(adjPosition);
          }
      }
      return -1;
  }
實現邏輯是,如果 position指向了headerView或 footerView,那么返回-1,否則,將返回在用戶view數組的位置。
也就是說
id= position-headerView的個數(id < headerviewer的個數+用戶view的個數),否則=-1
因此,OnItemClickListener的正確實現如下:

 

void onItemClick(AdapterViewparent, View view, int position, long id){
    if(id == -1) {
        // 點擊的是headerView或者footerView
        return;
    }
    int realPosition=(int)id;
    T item=getItem(realPosition);
    // 響應代碼
}

 

 

REFERENCES:http://blog.csdn.net/gg137608987/article/details/7995671


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM