Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的萬能適配器——base-adapter-helper解析

Android中的萬能適配器——base-adapter-helper解析

編輯:關於Android編程

在Android開發中,我們經常會用到ListView、GridView,每次編碼的時候都需要為他們寫對應的Adapter,寫多了就感覺很煩躁了,因為基本的編程思想都是一樣的,但是每次都要重復去寫,所以我們能不能把它們抽象成一個通用的模板,這樣就不用每次都重復寫相同的代碼了,直接重復使用,這樣不是更好,下面我們就來介紹介紹一個開源項目base-adapter-helper。

傳統Adapter的編碼思路,主要看Adapter中的getView方法。

 

public View getView(int pos, View convertView, ViewGroup parent){ 
    ViewHolder holder; 
    if (convertView == null) { 
        convertView = mInflater.inflate(R.layout.list_item, null); 
        holder = new ViewHolder();  
        holder.text = (TextView) convertView.findViewById(R.id.text)); 
        holder.icon = (ImageView) convertView.findViewButId(R.id.icon)); 
        convertView.setTag(holder); 
    } else { 
        holder = (ViewHolder) convertView.getTag(); 
    }  
    holder.text.setText(DATA[pos]); 
    holder.icon.setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2); 
    return convertView; 
}

static class ViewHolder { 
    TextView text; 
    ImageView icon; 
}

上面使用了一個ViewHolder用來緩存對應Item中的view,並且重用移出的Item,它對應的就是convertView。這樣注意為了節省資源,提高效率。這種寫法大家都應該很熟悉了。
下面來看看base-adapter-helper是怎樣對其進行抽象封裝的。首先來看看它的類繼承圖。

github鏈接:base-adapter-helper

\

可以看到BaseQuickAdapter繼承自BaseAdapter,同樣我們重點關注它的getView函數。

 

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (getItemViewType(position) == 0) {
        final H helper = getAdapterHelper(position, convertView, parent);
        T item = getItem(position);
        helper.setAssociatedObject(item);
        convert(helper, item);
        return helper.getView();
    }

    return createIndeterminateProgressView(convertView, parent);
}

private View createIndeterminateProgressView(View convertView, ViewGroup parent) {
    if (convertView == null) {
        FrameLayout container = new FrameLayout(context);
        container.setForegroundGravity(Gravity.CENTER);
        ProgressBar progress = new ProgressBar(context);
        container.addView(progress);
        convertView = container;
    }
    return convertView;
}

下面我們分析分析getView的代碼:

 

 

第3行代碼就是獲取該postion的Item類型,上面定義了兩種類型的Item,一種是我們需要顯示的View的Item,一種是底部的加載的View的Item。當Item類型為0是就為需要顯示的Item,當Item類型為1是就為底部加載的Item,上面的第11行代碼的createIndeterminateProgressView就是創建底部用來的加載的Item,可以看到它是一個ProgressBar。另外可以通過showIndeterminateProgress(boolean)來顯示或者隱藏這個item。
\ 第4行代碼的getAdapterHelper獲取一個BaseAdapterHelper對象,我們可以看到,在BaseQuickAdapter類中,getAdapterHelper是一個抽象函數,所以我們來看看BaseQuickAdapter的子類QuickAdapter,在這個類中它實現了getAdapterHelper方法,執行的實質是BaseAdapterHelper的靜態get方法。另外需要提到的是,QuickAdapter類的構造函數有一個參數為layoutResId,它就是傳入我們要顯示Item的布局文件。
static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
    if (convertView == null) {
        return new BaseAdapterHelper(context, parent, layoutId, position);
    }

    // Retrieve the existing helper and update its position
    BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag();
    existingHelper.position = position;
    return existingHelper;
}

從上面可以看到它也對convertView進行了重用,當convertView為null,那麼我們需要創建一個BaseAdapterHelper,傳入的就是要顯示的位置position以及layoutId布局文件,這個position為前面getView中的那個position參數,layoutId為創建QuickAdapter傳入的參數,就是Item的布局文件。
protected BaseAdapterHelper(Context context, ViewGroup parent, int layoutId, int position) {
    this.context = context;
    this.position = position;
    this.views = new SparseArray();
    convertView = LayoutInflater.from(context) //
            .inflate(layoutId, parent, false);
    convertView.setTag(this);
}
在BaseAdapterHelper的構造函數裡面,定義了一個views,它其實就是傳統Adapter裡面的那個ViewHolder用來存放Item裡面的各個view。convertView為我們要顯示的Item的View,接著通過setTag函數將BaseAdapterHelper對象本身關聯到convertView上面,所以我們知道每個Item對象都關聯了一個BaseAdapterHelper對象。
當convertView不為null的時候,我們就直接可以復用這個convertView,首先從convertView中取出它關聯的BaseAdapterHelper對象,這樣就可以復用這個convertView對應的BaseAdapterHelper對象。
接著分析最上面的代碼,第5行代碼getItem用來得到需要顯示的數據,這裡需要說明的是,我們應該把需要傳入的數據放在一個List中,我們可以看看QuickAdapter的構造函數
public QuickAdapter(Context context, int layoutResId, List data) {
    super(context, layoutResId, data);
}
可以看到我們傳入Item布局的layoutResId和要顯示的數據data,data是List類型的。 第6行代碼是將我們向顯示的數據項與BaseAdapterHelper對象關聯起來。
第7行代碼convert函數同樣是一個抽象函數,它需要我們進行實現,來具體設置對應的Item裡面的內容。
第8行代碼是當BaseAdapterHelper對象設置為Item裡面的內容之後,然後就可以得到這個Item的View對象進行返回。
下面我們來具體畫個圖來說明。假如我們要顯示的是一個ListView。
當剛開始顯示的時候,因為對應的convertView為null,所以會創建BaseAdapterHelper,核心代碼如下:
protected BaseAdapterHelper(Context context, ViewGroup parent, int layoutId, int position) {
    this.context = context;
    this.position = position;
    this.views = new SparseArray();
    convertView = LayoutInflater.from(context) //
            .inflate(layoutId, parent, false);
    convertView.setTag(this);
}
\
因為在BaseAdapterHelper對象中包含有對應的Item對應的convertView和對應的position以及convertView裡面的子view集合,因此我們可以直接通過BaseAdapterHelper對象來完成各項操作。 \   當List向上滑動的時候,第一個Item移出List,底部就需要再顯示一個Item,這個時候getView裡面的convertView就是第一個移出的View,我們可以直接對它重用來顯示下一個Item,核心代碼為:
BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag();
existingHelper.position = position;
他直接得到BaseAdapterHelper對象,然後重新設置它對應的位置postion,因為BaseAdapterHelper對象中引用到了重用的convertView,這樣就可以直接使用這個view的Item了。   下面來舉個簡單的例子:
public class MainActivity extends AppCompatActivity {
    private ListView listView;

    private List data = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        data.add("text1");
        data.add("text2");
        data.add("text3");
        data.add("text4");
        data.add("text5");
        data.add("text6");

        listView = (ListView) findViewById(R.id.listview);
        QuickAdapter adapter = new QuickAdapter(this, R.layout.item, data) {
            @Override
            protected void convert(BaseAdapterHelper helper, String item) {
                helper.setText(R.id.textView, item);
            }
        };
        listView.setAdapter(adapter);
    }
    
}

也就是說我們只需要定義一個QuickAdapter重寫convert方法就可以了,在convert方法裡面我們直接使用BaseAdapterHelper對象完成對數據內容item的設置就可以了。 \  

 

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