Android必學之數據適配器BaseAdapter

什麼是數據適配器?java

下圖展現了數據源、適配器、ListView等數據展現控件之間的關係。咱們知道,數據源是各類各樣的,而ListView所展現數據的格式則是有必定的要求的。數據適配器正是創建了數據源與ListView之間的適配關係,將數據源轉換爲ListView可以顯示的數據格式,從而將數據的來源與數據的顯示進行解耦,下降程序的耦合性。這也體現了Android的適配器模式的使用。對於ListView、GridView等數據展現控件有多種數據適配器,本文講解最通用的數據適配器——BaseAdapter。android

.ListView的顯示與緩存機制緩存

咱們知道,ListView、GridView等控件能夠展現大量的數據信息。假以下圖中的ListView能夠展現100條信息,可是屏幕的尺寸是有限的,一屏幕只能顯示下圖中的7條。當向上滑動ListView的時候,item1被滑出了屏幕區域,那麼系統就會將item1回收到Recycler中,即View緩衝池中,而將要顯示的item8則會從緩存池中取出佈局文件,並從新設置好item8須要顯示的數據,並放入須要顯示的位置。這就是ListView的緩衝機制,總結起來就是一句話:須要時才顯示,顯示完就被會收到緩存。ListView,GridView等數據顯示控件經過這種緩存機制能夠極大的節省系統資源。app

.BaseAdapteride

使用BaseAdapter比較簡單,主要是經過繼承此類來實現BaseAdapter的四個方法:佈局

public int getCount(): 適配器中數據集的數據個數;性能

public Object getItem(int position): 獲取數據集中與索引對應的數據項;優化

public long getItemId(int position): 獲取指定行對應的ID;this

public View getView(int position,View convertView,ViewGroup parent): 獲取沒一行Item的顯示內容。spa

下面經過一個簡單示例演示如何使用BaseAdapter。

1.建立佈局文件

activity_main.xml

複製代碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.cbt.learnbaseadapter.MainActivity">

    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</RelativeLayout>
複製代碼

item.xml (ListView中每條信息的顯示佈局)

複製代碼
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/iv_image"
        android:src="@mipmap/ic_launcher"
        android:layout_width="60dp"
        android:layout_height="60dp"/>
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_toEndOf="@id/iv_image"
        android:text="Title"
        android:gravity="center"
        android:textSize="25sp"/>

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/iv_image"
        android:layout_below="@id/tv_title"
        android:text="Content"
        android:textSize="20sp"/>
</RelativeLayout>
複製代碼

2.建立數據源

ItemBean.java

複製代碼
package com.cbt.learnbaseadapter;

/**
 * Created by caobotao on 15/12/20.
 */
public class ItemBean {
    public int itemImageResId;//圖像資源ID
    public String itemTitle;//標題
    public String itemContent;//內容

    public ItemBean(int itemImageResId, String itemTitle, String itemContent) {
        this.itemImageResId = itemImageResId;
        this.itemTitle = itemTitle;
        this.itemContent = itemContent;
    }
}
複製代碼

經過此Bean類,咱們就將要顯示的數據與ListView的佈局內容一一對應了,每一個Bean對象對應ListView的一條數據。這種方法在ListView中使用的很是普遍。

MainActivity.java

複製代碼
package com.cbt.learnbaseadapter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    ListView mListView ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        List<ItemBean> itemBeanList = new ArrayList<>();
        for (int i = 0;i < 20; i ++){
            itemBeanList.add(new ItemBean(R.mipmap.ic_launcher, "標題" + i, "內容" + i));
        }
        mListView = (ListView) findViewById(R.id.lv_main);
        //設置ListView的數據適配器
        mListView.setAdapter(new MyAdapter(this,itemBeanList));
    }
}
複製代碼

 

3.建立BaseAdapter

經過上面的講解,咱們知道繼承BaseAdapter須要從新四個方法:getCount、getItem、getItemId、getView。其中前三個都比較簡單,而getView稍微比較複雜。一般重寫getView有三種方式,這三種方法性能方面有很大的不一樣。接下來咱們使用此三種方式分別實現MyAdapter。

第一種:逗比式

複製代碼
package com.cbt.learnbaseadapter;
import android.content.Context;
import android.view.*;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;
/**
 * Created by caobotao on 15/12/20.
 */
public class MyAdapter extends BaseAdapter{
    private List<ItemBean> mList;//數據源
    private LayoutInflater mInflater;//佈局裝載器對象

    // 經過構造方法將數據源與數據適配器關聯起來
    // context:要使用當前的Adapter的界面對象
    public MyAdapter(Context context, List<ItemBean> list) {
        mList = list;
        mInflater = LayoutInflater.from(context);
    }

    @Override
    //ListView須要顯示的數據數量
    public int getCount() {
        return mList.size();
    }

    @Override
    //指定的索引對應的數據項
    public Object getItem(int position) {
        return mList.get(position);
    }

    @Override
    //指定的索引對應的數據項ID
    public long getItemId(int position) {
        return position;
    }

    @Override
    //返回每一項的顯示內容
    public View getView(int position, View convertView, ViewGroup parent) {
        //將佈局文件轉化爲View對象
        View view = mInflater.inflate(R.layout.item,null);

        /**
         * 找到item佈局文件中對應的控件 
         */
        ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
        TextView titleTextView = (TextView) view.findViewById(R.id.tv_title);
        TextView contentTextView = (TextView) view.findViewById(R.id.tv_content);

        //獲取相應索引的ItemBean對象
        ItemBean bean = mList.get(position);

        /**
         * 設置控件的對應屬性值 
         */
        imageView.setImageResource(bean.itemImageResId);
        titleTextView.setText(bean.itemTitle);
        contentTextView.setText(bean.itemContent);

        return view;
    }
}
複製代碼

爲何稱這種getView的方式是逗比式呢?

經過上面講解,咱們知道ListView、GridView等數據展現控件有緩存機制,而這種方式每次調用getView時都是經過inflate建立一個新的View對象,而後在此view中經過findViewById找到對應的控件,徹底沒有利用到ListView的緩存機制。這種方式沒有通過優化處理,對資源形成了極大的浪費,效率是很低的。

 

第二種:普通式

複製代碼
public View getView(int position, View convertView, ViewGroup parent) {//若是view未被實例化過,緩存池中沒有對應的緩存
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item,null);
        }
        /**
         * 找到item佈局文件中對應的控件
         */
        ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image);
        TextView titleTextView = (TextView) convertView.findViewById(R.id.tv_title);
        TextView contentTextView = (TextView) convertView.findViewById(R.id.tv_content);

        //獲取相應索引的ItemBean對象
        ItemBean bean = mList.get(position);
        /**
         * 設置控件的對應屬性值
         */
        imageView.setImageResource(bean.itemImageResId);
        titleTextView.setText(bean.itemTitle);
        contentTextView.setText(bean.itemContent);
        return convertView;
    }
複製代碼

此方式充分使用了ListView的緩存機制,若是view沒有緩存才建立新的view,效率相比於逗比式提高了不少。可是,當ListView很複雜時,每次調用findViewById都會去遍歷視圖樹,因此findViewById是很消耗時間的,咱們應該儘可能避免使用findViewById來達到進一步優化的目的。

 

第三種:文藝式

複製代碼
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;
    //若是view未被實例化過,緩存池中沒有對應的緩存
    if (convertView == null) {
        viewHolder = new ViewHolder();
        // 因爲咱們只須要將XML轉化爲View,並不涉及到具體的佈局,因此第二個參數一般設置爲null
        convertView = mInflater.inflate(R.layout.item, null);

        //對viewHolder的屬性進行賦值
        viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image);
        viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
        viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);

        //經過setTag將convertView與viewHolder關聯
        convertView.setTag(viewHolder);
    }else{//若是緩存池中有對應的view緩存,則直接經過getTag取出viewHolder
        viewHolder = (ViewHolder) convertView.getTag();
    }
    // 取出bean對象
    ItemBean bean = mList.get(position);

    // 設置控件的數據
    viewHolder.imageView.setImageResource(bean.itemImageResId);
    viewHolder.title.setText(bean.itemTitle);
    viewHolder.content.setText(bean.itemContent);

    return convertView;
}
// ViewHolder用於緩存控件,三個屬性分別對應item佈局文件的三個控件
class ViewHolder{
    public ImageView imageView;
    public TextView title;
    public TextView content;
}
複製代碼

此方式不只利用了ListView的緩存機制,並且使用ViewHolder類來實現顯示數據視圖的緩存,避免屢次調用findViewById來尋找控件,以達到優化程序的目的。因此,你們在平時的開發中應當儘可能使用這種方式進行getView的實現。

總結一下用ViewHolder優化BaseAdapter的總體步驟:

>1 建立bean對象,用於封裝數據;

>2 在構造方法中初始化的數據List;

>3 建立ViewHolder類,建立佈局映射關係;

>4 判斷convertView,爲空則建立,並設置tag,不爲空則經過tag取出ViewHolder;

>5 給ViewHolder的控件設置數據。

相關文章
相關標籤/搜索