Android UI - AdapterView 及其子類

AdapterView

  1. AdapterView 是一個(gè)抽象類魏颓,其派生的子類在用法上十分相似威蕉;
  2. AdapterView 繼承了 ViewGroup鼠证;
  3. AdapterView 及其子類的繼承關(guān)系如下:


  4. AdapterView 常用的實(shí)現(xiàn)類:
  • Spinner: 列表選擇框欺矫,當(dāng)需要用戶選擇的時(shí)候沈跨,可以提供一個(gè)列表將所有可選項(xiàng)列出來偷厦,供用戶選擇商叹。
  • ListView: 以垂直列表的形式顯示所有列表項(xiàng)。
  • GridView: 用于在界面上按行和列分布的方式來顯示多個(gè)組件只泼。

Adapter 接口及其實(shí)現(xiàn)類

  1. Adapter 是一個(gè)接口剖笙,其派生了 ListAdapter 和 SpinnerAdapter 兩個(gè)子接口。其中请唱,ListAdapter 為 AbsListView 提供列表項(xiàng)弥咪,而 SpinnerAdapter 為AbsSpinner 提供列表項(xiàng)过蹂;
  2. Adapter 及其實(shí)現(xiàn)類的繼承關(guān)系如下:


  3. Adapter 常用的實(shí)現(xiàn)類:
  • ArrayAdapter: 通常用于將數(shù)組或 List 集合的多個(gè)值包裝成多個(gè)列表項(xiàng)。
  • SimpleAdapter: 用于將 List 集合的多個(gè)對(duì)象包裝成多個(gè)列表項(xiàng)聚至。
  • SimpleCursorAdapter: 與 SimpleAdapter 類似酷勺,與數(shù)據(jù)庫打交道。
  • Base Adapter: 抽象類扳躬,通常用于被繼承脆诉,可以對(duì)個(gè)列表項(xiàng)進(jìn)行最大限度的定制。

Adapter 淺談


ArrayAdapter

ArrayAdapter(Context context, int resource, int textViewResourceId)

ArrayAdapter 三個(gè)參數(shù)說明:

  • context:整個(gè)應(yīng)用的上下文
  • resource:界面布局 ID坦报,代表一個(gè)布局樣式文件库说,控制列表項(xiàng)的外觀,此樣式文件只能有一個(gè) TextView片择,連 Layout 也不能有潜的;可以使用系統(tǒng)自帶的樣式文件(android.R.layout.xxx),也可以使用自定義的樣式文件(R.layout.xxx)
  • textViewResourceId:列表項(xiàng)中的數(shù)據(jù)

SimpleAdapter

SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

SimpleAdapter 五個(gè)參數(shù)說明:

  • context:整個(gè)應(yīng)用的上下文
  • data: List<? extends Map<String, ?>> 類型的集合對(duì)象字管,集合中每個(gè) Map<String, ?> 對(duì)象生成一個(gè)列表項(xiàng)
  • resource:界面布局 Id啰挪,代表一個(gè)布局樣式文件,該文件作為列表項(xiàng)的組件嘲叔,控制列表項(xiàng)的外觀
  • from:String[] 類型的參數(shù)亡呵,該參數(shù)決定提取 Map<String, ?> 對(duì)象中哪些 key 對(duì)應(yīng)的 value 來生成列表項(xiàng)
  • to:int[] 類型的參數(shù),該參數(shù)決定使用自定義布局中的哪些 View 組件來組合成一個(gè)列表項(xiàng)(數(shù)組里面的 id 是自定義布局中各個(gè)控件的 id硫戈,順序需要與上面的 from 中的順序?qū)?yīng))

BaseAdapter

繼承 BaseAdapter 時(shí)锰什,必須重寫它的 4 個(gè)方法,具體如下:

  • getCount():返回 adapter 中數(shù)據(jù)的個(gè)數(shù)丁逝,即返回列表項(xiàng)的行數(shù)
  • getItem(int position):獲得相應(yīng)數(shù)據(jù)集合中特定位置的數(shù)據(jù)項(xiàng)汁胆,即返回當(dāng)前 Item 顯示的數(shù)據(jù)
  • getItemId(int position):返回 Item 的 Id
  • getView(int position, View convertView, ViewGroup parent):每一個(gè) Item 項(xiàng)創(chuàng)建時(shí)被調(diào)用(即每一次 Item 從屏幕外滑進(jìn)屏幕內(nèi)的時(shí)候調(diào)用,或者程序剛開始的時(shí)候創(chuàng)建第一屏 Item 的時(shí)候調(diào)用)
  • position:界面上 Item 的 Id
  • convertView:展示在界面上的一個(gè) Item霜幼,可以用來緩存布局
  • parent:加載 XML 視圖時(shí)使用

Adapter 和 ViewAdapter 結(jié)合使用


Spinner (列表選擇框)

Spinner嫩码,顧名思義,當(dāng)需要用戶選擇的時(shí)候罪既,可以提供一個(gè)列表將所有可選項(xiàng)列出來铸题,供用戶選擇。

Spinner 的列表項(xiàng)數(shù)據(jù)的獲取方法有兩種琢感,一是直接在 XML 布局文件中為 android:entries 屬性指定數(shù)組作為數(shù)據(jù)源丢间,二是在代碼中通過 AdapterView 的 setAdapter(adapter) 設(shè)置。

1. 在 XML 布局中指定數(shù)組作為數(shù)據(jù)源

  1. 在 values 文件下新建一個(gè) arrays.xml 文件驹针,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>    
  <string-array name="phone_brand">       
    <item>HTC</item>        
    <item>iPhone</item>      
    <item>Samsung</item>     
    <item>Motorola</item>     
    <item>Huawei</item>    
    <item>Nokia</item>    
  </string-array>
</resources>
  1. 在 XML 布局文件中定義一個(gè) Spinner千劈,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
  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"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="net.monkeychan.spinnertest.MainActivity" > 
 
  <Spinner     
    android:layout_width="match_parent"    
    android:layout_height="wrap_content"  
    android:entries="@array/phone_brand" />  
</LinearLayout>

注: android:spinnerMode 屬性可以設(shè)置 Spinner 的樣式,當(dāng)設(shè)置為 android:spinnerMode="dropdown" 時(shí)牌捷,為下拉樣式墙牌;當(dāng)設(shè)置 android:spinnerMode="dialog" 時(shí)涡驮,為彈出選擇框樣式,此時(shí)可以添加屬性 android:prompt喜滨,為彈出的選擇框添加標(biāo)題捉捅。

A. 設(shè)置為 android:spinnerMode="dropdown",即下拉樣式

  • XML 文件布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.monkeychan.spinnertest.MainActivity" >

 <Spinner     
   android:layout_width="match_parent"    
   android:layout_height="wrap_content"  
   android:entries="@array/phone_brand" 
   android:spinnerMode="dropdown" />  

</LinearLayout>


- 效果演示:
![](http://upload-images.jianshu.io/upload_images/1850626-3bc5c82887f05972.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

B. 設(shè)置為 android:spinnerMode="dialog"虽风,即彈出選擇框樣式

- XML 文件布局:
- ```
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="net.monkeychan.spinnertest.MainActivity" > 
 
    <Spinner     
       android:layout_width="match_parent"    
       android:layout_height="wrap_content"  
       android:entries="@array/phone_brand" 
       android:spinnerMode="dialog"
       android:prompt="@string/select_phone_brand" />  
</LinearLayout>

上面代碼中棒口,android:prompt 屬性用于設(shè)置彈出選擇框的標(biāo)題。注意辜膝,此處只能引用字符串變量已球,而不能直寫標(biāo)題的內(nèi)容篡诽,否則編譯時(shí)會(huì)出錯(cuò)竟终。

  • 效果演示:


2. 在代碼中通過 AdapterView 的 setAdapter(adapter) 設(shè)置

  • XML 文件布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.monkeychan.spinnertest.MainActivity" >

<TextView
    android:layout_width="wrap_content"    
    android:layout_height="wrap_content"
    android:text="請(qǐng)選擇城市:" />

<Spinner     
    android:id="@+id/spinner"
    android:layout_width="match_parent"    
    android:layout_height="wrap_content" />  

</LinearLayout>


- Java 代碼:

public class MainActivity extends AppcompatActivity {

private String[] location = { "北京", "廣東", "浙江", "四川", "海南", "福建" };

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 1. 從布局中獲取到 Spinner 的實(shí)例
    Spinner spinner = (Spinner) findViewById(R.id.spinner);
    
    // 2. 創(chuàng)建一個(gè) ArrayAdapter 的對(duì)象卧檐,并進(jìn)行初始化
    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_dropdown_item, location);
    
    // 3. 為 Spinner 設(shè)置 Adapter
    spinner.setAdapter(arrayAdapter);

}

}


- 效果演示:
![](http://upload-images.jianshu.io/upload_images/1850626-aaeb4b21cfc48c75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

上面的代碼中我們使用了 ArrayAdapter,實(shí)際上也可以使用其它 Adapter忱辅,如 SimpleAdapter七蜘、擴(kuò)展 BaseAdapter 等,道理是一樣的墙懂。

##GridView 

> 1. GridView橡卤,即網(wǎng)格視圖,用于在界面上按行损搬、列分布的方式來顯示多個(gè)組件;
> 2. GridView 默認(rèn)為一列碧库,如果想要顯示多列,需要在 XML 布局中為屬性 android:numColumns 或在代碼中 使用方法 setNumColumns(int) 指定列數(shù)巧勤,而行數(shù)是動(dòng)態(tài)改變的嵌灰,無需指定。

**值得注意的是踢关,雖然 GridView 和 ListView 一樣繼承了 AbsListView,但 GridView 并沒有 android:entries 屬性粘茄,所以我們不能在 XML 布局中為 GridView 指定數(shù)據(jù)源签舞,只能在代碼中通過 AdapterView 的 setAdapter(adapter) 設(shè)置。**

下面是我們要達(dá)到的效果:
![](http://upload-images.jianshu.io/upload_images/1850626-bb0805dbe83e463f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**注:** 這次我們使用 SimpleAdapter 來實(shí)現(xiàn)柒瓣。

**下面我們以水果為例儒搭,圖片為水果圖片,文字為水果名稱**

1) 由于圖中有行和列芙贫,所以我們可以使用 GridView 來實(shí)現(xiàn)搂鲫,從圖中可以看出,總共有 3 列磺平。下面是 XML 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.monkeychan.gridviewtest.MainActivity">

<GridView
    android:id="@+id/gridView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:numColumns="3" />

</LinearLayout>


2) 自定義樣式文件魂仍,該文件作為列表項(xiàng)的組件拐辽,控制列表項(xiàng)的外觀:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal">

<!-- 自定義一個(gè) ImageView,用來顯示圖片 -->
<ImageView
    android:id="@+id/fruit_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<!-- 自定義一個(gè) TextView擦酌,用來顯示文字 -->
<TextView
    android:id="@+id/fruit_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="5dp" />

</LinearLayout>


3) Java 代碼:

public class MainActivity extends AppCompatActivity {

// 定義一個(gè) int 型數(shù)組俱诸,用來存放水果對(duì)應(yīng)圖片的資源 id
private int[] images = {R.drawable.apple_pic, R.drawable.banana_pic, R.drawable.cherry_pic,
        R.drawable.grape_pic, R.drawable.mango_pic, R.drawable.orange_pic, R.drawable.pear_pic,
        R.drawable.pineapple_pic, R.drawable.strawberry_pic};

// 定義一個(gè) String 類型的數(shù)組,用來存放水果的名稱
private String[] names = {"蘋果", "香蕉", "櫻桃", "葡萄", "芒果", "香橙", "雪梨", "菠蘿", "草莓"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 創(chuàng)建一個(gè) List 集合赊舶,List 集合的元素是 Map
    List<Map<String, Object>> listItems = new ArrayList<Map<String,Object>>();
    for(int i=0;i<names.length;i++){
        // 創(chuàng)建一個(gè) Map 集合睁搭,用來存放水果圖片和水果名稱
        Map<String, Object> listItem = new HashMap<String, Object>();
        listItem.put("images", images[i]);
        listItem.put("names", names[i]);
        listItems.add(listItem);
    }

    // 1. 從布局中獲取到 GridView 的實(shí)例
    GridView gridView = (GridView) findViewById(R.id.gridView);

    // 2. 創(chuàng)建一個(gè) SimpleAdapter 的實(shí)例,并進(jìn)行初始化
    SimpleAdapter simpleAdapter = new SimpleAdapter(
            this, listItems, R.layout.gridview_item, new String[] {"images", "names", new int[] {R.id.fruit_image, R.id.fruit_name});

    // 3. 為 GridView 設(shè)置 Adapter
    gridView.setAdapter(simpleAdapter);
}

}


4) 效果演示:
![](http://upload-images.jianshu.io/upload_images/1850626-656aa33769ebc904.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

上面的代碼中我們使用了 SimpleAdapter笼平,實(shí)際上也可以使用其它 Adapter园骆,如 ArrayAdapter、擴(kuò)展 BaseAdapter 等寓调,道理是一樣的锌唾。

##ListView 

> ListView ,以**垂直列表**的形式顯示所有列表項(xiàng)捶牢。

**與 Spinner 類似鸠珠,ListView 的列表項(xiàng)數(shù)據(jù)的獲取方法有兩種,一是直接在 XML 布局文件中為 android:entries 屬性指定數(shù)組作為數(shù)據(jù)源秋麸,二是在代碼中通過 AdapterView 的 setAdapter(adapter) 設(shè)置渐排。**

###1. 在 XML 布局中指定數(shù)組作為數(shù)據(jù)源

1) 在 values 文件下新建一個(gè) arrays.xml 文件,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="phone_brand">
<item>HTC</item>
<item>iPhone</item>
<item>Samsung</item>
<item>Motorola</item>
<item>Huawei</item>
<item>Nokia</item>
</string-array>
</resources>


2) 在 XML 布局文件中定義一個(gè) ListView灸蟆,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.monkeychan.listviewtest.MainActivity" >

<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/phone_brand" />
</LinearLayout>


3) 效果演示:
![](http://upload-images.jianshu.io/upload_images/1850626-26b5c3453e919a75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###2. 在代碼中通過 AdapterView 的 setAdapter(adapter) 設(shè)置

下面是我們要達(dá)到的效果:
![](http://upload-images.jianshu.io/upload_images/1850626-1711afd8450d830e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**注:** 這次我們使用自定義 Adapter驯耻。

**下面我們?nèi)匀灰运麨槔瑘D片為水果圖片炒考,文字為水果名稱**

1) 首先定義我們自己的 Adapter可缚,從圖中可以看出,Adapter 中要有文字和圖片斋枢,所以我們可以用一個(gè) List<String> 類型的集合和 List<Integer> 類型的集合來存放文字和圖片(因?yàn)樵?R.java 文件中圖片資源的 id 是 int 類型的)帘靡。自定義的 Adapter 如下:

public class MyListViewAdapter extends BaseAdapter {

private Context mContext;
private int mResource;
private List<Integer> mImage;
private List<String> mText;

public MyListViewAdapter(Context context, int resource, List<Integer> image, List<String> text) {
    mContext = context;
    mResource = resource;
    mText = text;
    mImage = image;
}

@Override
public int getCount() {
    return mText.size();
}

@Override
public Object getItem(int position) {
    return mText.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // LayoutInflater,布局加載器瓤帚,用來加載從外部傳進(jìn)來的布局
    convertView = LayoutInflater.from(mContext).inflate(mResource, null);
    // 注意描姚,外部傳進(jìn)來的布局文件中必須要有 id 為 fruit_image 的 ImageView 和 id 為 fruit_name 的 TextView,
    // 否則會(huì)出現(xiàn) NullPointerException 錯(cuò)誤戈次,即空指針
    ImageView iv = (ImageView) convertView.findViewById(R.id.fruit_image);
    TextView tv = (TextView) convertView.findViewById(R.id.fruit_name);
    iv.setImageResource(mImage.get(position));
    tv.setText(mText.get(position));
    return convertView;
}

}


2) XML 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.monkeychan.listviewtest.MainActivity">

<ListView
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</LinearLayout>


3) 自定義樣式文件轩勘,該文件作為列表項(xiàng)的組件,控制列表項(xiàng)的外觀:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<ImageView
    android:id="@+id/fruit_image"
    android:layout_width="36dp"
    android:layout_height="36dp" />

<TextView
    android:id="@+id/fruit_name"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="10dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="16sp"/>

</LinearLayout>


4) Java 代碼:

public class MainActivity extends AppCompatActivity {

// 定義一個(gè) int 型數(shù)組怯邪,用來存放水果圖片的 id绊寻,圖片文件放在 drawable 文件夾下
private int[] images = {R.drawable.apple_pic,
        R.drawable.banana_pic, R.drawable.cherry_pic,
        R.drawable.grape_pic, R.drawable.mango_pic,
        R.drawable.orange_pic, R.drawable.pear_pic,
        R.drawable.pineapple_pic, R.drawable.strawberry_pic,
        R.drawable.watermelon_pic};

// 定義一個(gè)String 類型數(shù)組,用來存放水果名稱
private String[] names = {"蘋果", "香蕉", "櫻桃", "葡萄", "芒果", "香橙",
        "雪梨", "菠蘿", "草莓", "西瓜"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 創(chuàng)建一個(gè) List<Integer> 集合,用來存放水果圖片
    List<Integer> imagesList = new ArrayList<>();
    for (int i = 0; i < images.length; i++) {
        imagesList.add(images[i]);
    }

    // 創(chuàng)建一個(gè) List<String> 集合澄步,用來存放水果名稱
    List<String> namesList = new ArrayList<>();
    for (int i = 0; i < names.length; i++) {
        namesList.add(names[i]);
    }

    // 1. 從布局中獲取到 ListView 的實(shí)例
    ListView listView = (ListView) findViewById(R.id.listView);

    // 2. 創(chuàng)建一個(gè) MyListViewAdapter 的對(duì)象冰蘑,并進(jìn)行初始化
    MyListViewAdapter myListViewAdapter = new MyListViewAdapter(this, R.layout.listview_item, imagesList, namesList);

    // 3. 為 ListView 設(shè)置 Adapter
    listView.setAdapter(myListViewAdapter);
}

}


5) 效果演示:
![](http://upload-images.jianshu.io/upload_images/1850626-5cbd0c0cdcbd4eb7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

上面的代碼中我們使用了自定義 Adapter,實(shí)際上也可以使用其它 Adapter驮俗,如 ArrayAdapter懂缕、擴(kuò)展 BaseAdapter 等,道理是一樣的王凑。

##自定義 Adapter 的優(yōu)化——提升 AdapterView 的運(yùn)行效率

以上面的 ListView 的為例搪柑,我們自定義了一個(gè) Adapter,來看看我們的 getView() 方法:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// LayoutInflater索烹,布局加載器工碾,用來加載從外部傳進(jìn)來的布局
convertView = LayoutInflater.from(mContext).inflate(mResource, null);
ImageView iv = (ImageView) convertView.findViewById(R.id.fruit_image);
TextView tv = (TextView) convertView.findViewById(R.id.fruit_name);
iv.setImageResource(mImage.get(position));
tv.setText(mText.get(position));
return convertView;
}


前面我們說過,getView() 方法是每一個(gè) Item 項(xiàng)創(chuàng)建時(shí)被調(diào)用百姓,并且在 getView() 方法中渊额,我們每次都將布局重新加載了一遍。當(dāng)我們的 Item 項(xiàng)數(shù)目超出屏幕可顯示范圍時(shí)垒拢,而我們又來回滑動(dòng) ListView 時(shí)旬迹,其實(shí)是多個(gè) Item 項(xiàng)在被反復(fù)創(chuàng)建、同一個(gè)布局在被反復(fù)加載求类,而每一次創(chuàng)建 Item 項(xiàng)奔垦、加載布局時(shí),就會(huì)消耗一次系統(tǒng)資源尸疆,這對(duì)系統(tǒng)來說是極大的開銷椿猎。當(dāng)多次滑動(dòng)過后,有可能造成滑動(dòng)的過程中出現(xiàn)卡頓寿弱,造成的用戶體驗(yàn)非常不好犯眠。那么,有沒有這種可能症革,將之前已經(jīng)創(chuàng)建好的 Item 項(xiàng)和已經(jīng)加載過的布局緩存起來筐咧,當(dāng)再次使用時(shí),只須從緩存中拿出來使用噪矛,而不用再次創(chuàng)建呢量蕊?這就是下面我們要做的。

1. 首先摩疑,我們要對(duì)布局進(jìn)行緩存:
我們可以在調(diào)用 getView() 方法時(shí)進(jìn)行判斷危融,如果緩存中不存在布局畏铆,我們才去加載布局雷袋,否則不加載。getView() 方法中有一個(gè) convertView 參數(shù),這個(gè)參數(shù)用于將之前加載好的布局進(jìn)行緩存楷怒,以便進(jìn)行重用蛋勺。至此,布局緩存的問題解決了鸠删。但是抱完,在 getView() 方法中,我們每次都會(huì)調(diào)用 findViewById() 方法來獲取控件的實(shí)例刃泡,這部分還可以優(yōu)化巧娱;

2. 其次,對(duì)控件實(shí)例進(jìn)行緩存:
我們可以定義這樣一個(gè)類烘贴,它負(fù)責(zé)緩存控件的實(shí)例禁添,我們給這個(gè)類取名叫 ViewHolder,當(dāng) convertView 為空(即緩存中不存在布局)時(shí)桨踪,創(chuàng)建一個(gè) ViewHolder 對(duì)象老翘,將控件的實(shí)例存儲(chǔ)在 ViewHolder 中。

**下面是改寫后的自定義 Adapter:**

public class MyListViewAdapter extends BaseAdapter {

private Context mContext;
private int mResource;
private List<Integer> mImage;
private List<String> mText;

public MyListViewAdapter(Context context, int resource, List<Integer> image, List<String> text) {
    mContext = context;
    mResource = resource;
    mText = text;
    mImage = image;
}

@Override
public int getCount() {
    return mText.size();
}

@Override
public Object getItem(int position) {
    return mText.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;
    // 判斷 convertView 是否為空
    if (convertView == null) {
        // LayoutInflater锻离,布局加載器铺峭,用來加載從外部傳進(jìn)來的布局
        convertView = LayoutInflater.from(mContext).inflate(mResource, null);
        // 創(chuàng)建 ViewHolder 的對(duì)象
        viewHolder = new ViewHolder();
        // 將控件實(shí)例存儲(chǔ)在 ViewHolder 中
        viewHolder.iv = (ImageView) convertView.findViewById(R.id.fruit_image);
        viewHolder.tv = (TextView) convertView.findViewById(R.id.fruit_name);
        // 將 ViewHolder 存儲(chǔ)在 convertView 中,即緩存布局
        convertView.setTag(viewHolder);
    } else {
        // 重新獲取 ViewHolder
        viewHolder = (ViewHolder) convertView.getTag();
    }
    viewHolder.iv.setImageResource(mImage.get(position));
    viewHolder.tv.setText(mText.get(position));
    return convertView;
}

// 創(chuàng)建一個(gè)內(nèi)部類 ViewHolder汽纠,用來緩存控件實(shí)例
class ViewHolder {
    ImageView iv;
    TextView tv;
}

}


##總結(jié)

**AdapterView 和 Adapter 結(jié)合使用的步驟:**
1. 從布局中獲取到 AdapterView 的實(shí)例卫键,即 findViewById();
2. 創(chuàng)建適合的 Adapter 對(duì)象疏虫,并進(jìn)行初始化(根據(jù) Adapter 的構(gòu)造方法的參數(shù)列表傳入對(duì)應(yīng)的參數(shù)類型)永罚;
3. 為 AdapterView 設(shè)置 Adapter;
4. 當(dāng)自定義 Adapter 時(shí)卧秘,應(yīng)注意優(yōu)化方面的問題呢袱。

----
參考資料:
- [《瘋狂 Android 講義》- 李剛](http://www.crazyit.org)
- [《第一行代碼——Android》- 郭霖](http://guolin.tech)
- [Android ArrayAdapter 詳解 - 彭香香的專欄](http://blog.csdn.net/nairuohe/article/details/6457300)
- [Android ListView使用BaseAdapter與ListView的優(yōu)化](http://www.open-open.com/lib/view/open1339485728006.html)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翅敌,隨后出現(xiàn)的幾起案子羞福,更是在濱河造成了極大的恐慌,老刑警劉巖蚯涮,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件治专,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡遭顶,警方通過查閱死者的電腦和手機(jī)张峰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棒旗,“玉大人喘批,你說我怎么就攤上這事。” “怎么了饶深?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵餐曹,是天一觀的道長。 經(jīng)常有香客問我敌厘,道長台猴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任俱两,我火速辦了婚禮饱狂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宪彩。我一直安慰自己嗡官,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布毯焕。 她就那樣靜靜地躺著衍腥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纳猫。 梳的紋絲不亂的頭發(fā)上婆咸,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音芜辕,去河邊找鬼尚骄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侵续,可吹牛的內(nèi)容都是我干的倔丈。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼状蜗,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼需五!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起轧坎,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤宏邮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后缸血,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜜氨,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年捎泻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了飒炎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笆豁,死狀恐怖郎汪,靈堂內(nèi)的尸體忽然破棺而出定欧,到底是詐尸還是另有隱情,我是刑警寧澤怒竿,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站扩氢,受9級(jí)特大地震影響耕驰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜录豺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一朦肘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧双饥,春花似錦媒抠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至昏翰,卻和暖如春苍匆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棚菊。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工浸踩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人统求。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓检碗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親码邻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子折剃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容