BaseAdapter是一種使用頻率較高的適配器,由於它能夠經過自定義最大程度擴展知足各類情景下的使用。咱們不只須要知道適配器的使用,進一步咱們也須要了解適配器的原理。java
問題是最好的學習方式,下面主要討論這麼幾個問題:android
Q1.ListView中每一個Item的建立app
Q2.ListView中Item的複用ide
Q3.ListView中屏幕顯示的Item與複用生成Item之間的關係post
首先寫一個簡單的demo.學習
1 package com.aellenlei.baseadapterdemo; 2 3 import android.support.v7.app.AppCompatActivity; 4 import android.os.Bundle; 5 import android.widget.ListView; 6 7 import java.util.ArrayList; 8 import java.util.List; 9 10 public class MainActivity extends AppCompatActivity { 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 17 //1.findViewById 18 ListView listView = (ListView) findViewById(R.id.listView); 19 20 //2.初始化數據源 21 List<ItemBean> list = new ArrayList<>(); 22 for (int i = 0; i < 5; i++) { 23 ItemBean itemBean = new ItemBean(); 24 itemBean.postion = i; 25 itemBean.title = "title " + i; 26 itemBean.content = "content " + i; 27 list.add(itemBean); 28 } 29 30 //3.初始化適配器 31 ItemBeanAdapter itemBeanAdapter = new ItemBeanAdapter(list, getApplicationContext()); 32 33 //4.ListView綁定適配器 34 listView.setAdapter(itemBeanAdapter); 35 } 36 }
1 package com.aellenlei.baseadapterdemo; 2 3 import android.content.Context; 4 import android.util.Log; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8 import android.widget.BaseAdapter; 9 import android.widget.CheckBox; 10 import android.widget.ImageView; 11 import android.widget.TextView; 12 13 import java.util.List; 14 15 /** 16 * User AellenLei 17 * NAME ItemBeanAdapter 18 * DATE 2016/3/7 19 */ 20 public class ItemBeanAdapter extends BaseAdapter { 21 22 private List<ItemBean> mData; 23 private Context mContext; 24 25 public ItemBeanAdapter(List<ItemBean> mData, Context mContext) { 26 this.mData = mData; 27 this.mContext = mContext; 28 } 29 30 @Override 31 public int getCount() { 32 return mData == null ? 0 : mData.size(); 33 } 34 35 @Override 36 public ItemBean getItem(int position) { 37 return mData.get(position); 38 } 39 40 @Override 41 public long getItemId(int position) { 42 return position; 43 } 44 45 @Override 46 public View getView(int position, View convertView, ViewGroup parent) { 47 48 Log.d("msg", position + "," + getItem(position).postion + "," + getItem(position).title + ". " 49 + ((convertView == null) ? ("covertView = null") : 50 (((TextView) convertView.findViewById(R.id.item_title)).getText().toString())) 51 ); 52 53 54 View ret; 55 56 if (convertView != null) { 57 ret = convertView; 58 } else { 59 ret = LayoutInflater.from(mContext).inflate(R.layout.item, null); 60 ViewHolder holder = new ViewHolder(); 61 holder.itemIcon = (ImageView) ret.findViewById(R.id.item_icon); 62 holder.itemTitle = (TextView) ret.findViewById(R.id.item_title); 63 holder.itemContent = (TextView) ret.findViewById(R.id.item_content); 64 holder.itemDate = (TextView) ret.findViewById(R.id.item_date); 65 holder.itemChecked = (CheckBox) ret.findViewById(R.id.item_check); 66 ret.setTag(holder); 67 } 68 69 ViewHolder viewHolder = (ViewHolder) ret.getTag(); 70 71 ItemBean itemBean = getItem(position); 72 73 viewHolder.itemIcon.setImageResource(R.mipmap.ic_launcher); 74 viewHolder.itemTitle.setText(itemBean.title); 75 viewHolder.itemContent.setText(itemBean.content); 76 viewHolder.itemDate.setText("yyyy-MM-dd"); 77 viewHolder.itemChecked.setChecked(itemBean.check); 78 79 return ret; 80 } 81 82 private static class ViewHolder { 83 private ImageView itemIcon; 84 private TextView itemTitle; 85 private TextView itemContent; 86 private TextView itemDate; 87 private CheckBox itemChecked; 88 } 89 }
1 package com.aellenlei.baseadapterdemo; 2 3 /** 4 * User AellenLei 5 * NAME ItemBean 6 * DATE 2016/3/7 7 */ 8 public class ItemBean { 9 public int postion; 10 public String url; 11 public String title; 12 public String content; 13 public String date; 14 public boolean check; 15 }
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:paddingBottom="@dimen/activity_vertical_margin" 7 android:paddingLeft="@dimen/activity_horizontal_margin" 8 android:paddingRight="@dimen/activity_horizontal_margin" 9 android:paddingTop="@dimen/activity_vertical_margin" 10 tools:context=".MainActivity"> 11 12 <ListView 13 android:id="@+id/listView" 14 android:layout_width="match_parent" 15 android:layout_height="match_parent"/> 16 </RelativeLayout>
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:padding="8dp"> 6 7 <ImageView 8 android:id="@+id/item_icon" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:src="@mipmap/ic_launcher" 12 android:padding="4dp"/> 13 14 <TextView 15 android:id="@+id/item_title" 16 android:layout_width="wrap_content" 17 android:layout_height="wrap_content" 18 android:textSize="20sp" 19 android:textStyle="bold" 20 android:layout_toRightOf="@id/item_icon" 21 android:layout_alignTop="@id/item_icon"/> 22 <TextView 23 android:id="@+id/item_content" 24 android:layout_width="wrap_content" 25 android:layout_height="wrap_content" 26 android:textSize="16sp" 27 android:layout_below="@id/item_title" 28 android:layout_toRightOf="@id/item_icon" 29 android:layout_alignBottom="@id/item_icon"/> 30 31 <TextView 32 android:id="@+id/item_date" 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content" 35 android:layout_toRightOf="@id/item_title" 36 android:layout_alignParentRight="true" 37 android:gravity="right"/> 38 <CheckBox 39 android:id="@+id/item_check" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:text="@null" 43 android:layout_below="@id/item_date" 44 android:layout_alignParentRight="true" 45 android:gravity="center" 46 android:layout_alignBottom="@id/item_content"/> 47 </RelativeLayout>
因爲該Demo比較簡單,不需多講相信均可以看懂。測試
ItemBeanAdapter.java的getView方法中有這麼一句:this
分別打印的是ListView中每個Item在ListView中的位置(默認從0開始,下同),該Item顯示的數據源中指定位置數據的poistion和title,convertView是否爲空若不爲空打印convertView以前顯示的title.url
當數據源中的數據條數爲5時,Logcat的日誌:spa
UI:
當數據源中的數據條數爲10是,Logcat的日誌:
UI:
根據這兩種狀況的測試,能夠大概回答第一個問題:
Q1.ListView中每一個Item的建立
A1.Adapter第一次建立的Items的數量是由手機屏幕的大小(可測試)和數據源數據的條數來決定的,也就是屏幕實際顯示多少個Item就建立幾個item的,很少建立新的item也很多建立新的item,items數量是屏幕實際顯示數目的取整。將下面的完整結合來看,第一次建立的Item是最基本的Item,它的數量是肯定的,之後新的item不管是向上滑動出現仍是向下滑動出現都是複用第一次建立的items中的某個item。
Q2.ListView中Item的複用
A2:最核心的代碼就是Adapter中的getView方法,它返回的是一個已經綁定好數據的view,而系統僅僅只是將這個view在屏幕的指定位置繪製出來。
代碼不是固定死的,固然你能夠有本身的寫法,可是原理老是相同的:
A2:當ListView第一次建立一屏幕的items時,covertView始終爲null(代碼測試很容易得出),因此當covertView爲空時,就須要將第一次建立一屏幕的items的每一個item「初始化」,這裏的「初始化」是將covertView和ViewHolder綁定起來,注意不管是將covertView和ViewHolder綁定起來仍是ret和ViewHolder綁定起來,它們的本質是同樣的,最後返回值是已經與ViewHolder綁定的View視圖,當掌握了covertView的複用寫法,能夠說是基本上item的複用的寫法也掌握了。
注意下面一種狀況,當ListView向上滑動,且item0徹底不見,item7和item8出現(下圖item8已經出現,只是沒有徹底顯示)的狀況:
此時Logcat打印的日誌:
根據以前的第一次建立items打印的日誌比較:item7仍然是新建立的,可是item8倒是複用的,item8複用的是item0(徹底根據日誌得出的)。(PS 可能此處有疑問,下面會分析)
A2:當listView向上滑動或者是向下滑動的時候,此時可能會出現item複用的狀況(注意此時可能會出現複用的狀況,不必定或出現哦)。若covertView不爲空,就能夠以前在該covertView初始化或複用中經過getTag方法,取出與之綁定的ViewHolder,從而實現減小findViewById的時間,findViewById是須要耗費時間的,當listView顯示大量的數據,此時的findViewByid能夠極大的提升效率。
最後分析總結前面的,能夠回答第三個問題:
Q3.ListView中屏幕顯示的Item與複用生成Item之間的關係
A3:ListView實際建立item的數量是由手機屏幕的大小和數據源的數據數量來決定的,準確的將這是不許確的或是錯誤的。
ListView在整個複用過程當中本質上實際建立item的數量(這裏所指的所有是最原始最本質的item)是由手機屏幕的大小、數據源的數據數量和每一個item實際的大小來決定的(固然這裏不考慮其餘更爲負責的狀況,而是假定每一個item的大小相同)。
用能夠惟一衡量肯定的話說是:本質上items的數量是當第一個item徹底消失後,此時Adapter總共建立的items數量,從本質上來講,這就是ListView在整個複用過程當中複用的item的數量。假如從0,1,...,n-1(n爲最原始的item數量)來看,當ListView向上滑動時,複用tem的順序是按順序複用0,1,...,n-1,每次複用一個;當ListView向下滑動時,複用的順序是按照逆序的,從n-1,n-2,..,0,也是一個一個複用的。
固然還有更爲複雜的狀況或者說從更爲本質也就是源碼的角度分析,這裏暫不考慮,而是從一種最爲表象或者最最最基本最最簡單來分析ListView與Adapter。