Android笔记(二十五) ListView的缓存机制与BaseAdapter
? ? ? ?之前接觸了ListView和Adapter,Adapter將數據源和View連接起來,實際應用中,我們要顯示的數據往往有很多,而屏幕只有那么大,系統只能屏幕所能顯示的內容,當我們滑動屏幕,會將舊的內容放入到緩沖池中,再從緩存池中拿出新的內容顯示出來,這就是ListView的緩存機制,這一機制可以極大的節省系統資源。
BaseAdapter
?????? BaseAdapter通常用于被擴展,擴展BaseAdapter可以對各項列表進行最大限度的定制。
?????? 我們可以用自己的類去繼承BaseAdapter,然后實現getCount()、getItem()、getItemId()、getView()這四個方法,來完成對Adapter的定制。
?????? getCount()??? 該方法返回ListView需要顯示的數據量
?????? getItem()????? 該方法返回指定索引(position)所對應的數據項
?????? getItemId()? 該方法返回對應的索引
?????? getView()????? 該方法返回每一項所顯示的內容
簡單示例:
package cn.lixyz.baseadaptertest;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast;import java.util.ArrayList; import java.util.List;public class MainActivity extends AppCompatActivity {List<ItemBean> itemBeanList;ListView listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);itemBeanList = new ArrayList<ItemBean>();for (int i = 0; i < 20; i++) {ItemBean ib = new ItemBean(R.drawable.icon, "標題" + i, "內容" + i);itemBeanList.add(ib);}listView = (ListView) findViewById(R.id.listView);listView.setAdapter(new MyAdapter(this, itemBeanList));listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Toast.makeText(MainActivity.this, "你選擇的是:" + position, Toast.LENGTH_SHORT).show();}});} } MainActivity.java <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"tools:context=".MainActivity"><ListViewandroid:id="@+id/listView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout> layout_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_icon"android:layout_width="60dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:layout_marginTop="10dp"android:src="@drawable/icon" /><TextViewandroid:id="@+id/tv_name"android:layout_width="match_parent"android:layout_height="35dp"android:layout_marginTop="10dp"android:layout_toEndOf="@+id/iv_icon"android:gravity="center"android:text="標題"android:textSize="25dp" /><TextViewandroid:id="@+id/tv_desc"android:layout_width="match_parent"android:layout_height="25dp"android:layout_below="@+id/tv_name"android:layout_marginLeft="10dp"android:layout_toEndOf="@+id/iv_icon"android:gravity="center"android:text="內容內容內容內容" /></RelativeLayout> layout_item.xml package cn.lixyz.baseadaptertest;/*** Created by LGB on 2015/9/9.*/ public class ItemBean {public int ItemImageResid;public String ItemName;public String Itemdesc;public ItemBean(int ItemImageResid, String ItemName, String Itemdesc) {this.ItemImageResid = ItemImageResid;this.ItemName = ItemName;this.Itemdesc = Itemdesc;} } ItemBean.java package cn.lixyz.baseadaptertest;import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;import java.util.List;/*** Created by LGB on 2015/9/9.*/ public class MyAdapter extends BaseAdapter {private List<ItemBean> list;private LayoutInflater inflater;public MyAdapter(Context context, List<ItemBean> list) {this.list = list;inflater = LayoutInflater.from(context);}//該方法返回ListView需要顯示的數據量 @Overridepublic int getCount() {return list.size();}//該方法返回指定索引(position)所對應的數據項 @Overridepublic Object getItem(int position) {return list.get(position);}//該方法返回對應的索引 @Overridepublic long getItemId(int position) {return 0;}// @Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = inflater.inflate(R.layout.laytou_item, null);ImageView imageView = (ImageView) view.findViewById(R.id.iv_icon);TextView name = (TextView) view.findViewById(R.id.tv_name);TextView desc = (TextView) view.findViewById(R.id.tv_desc);imageView.setImageResource(list.get(position).ItemImageResid);name.setText(list.get(position).ItemName);desc.setText(list.get(position).Itemdesc);return view;} } MyAdapter.java運行結果:
?
? ? ? ?上面的代碼中,我們可以看到一個ListView中的每一項都是我們直接使用Inflater新建并返回的,完全沒有使用到ListView提供的緩存機制
View view = inflater.inflate(R.layout.laytou_item, null); ...... return view;? ? ? ?有關inflater的內容,可以看這里:<轉> Android LayoutInflater詳解? ? ??Android 中LayoutInflater的使用
?
? ? ? ?我們稍對代碼做一下修改:
package cn.lixyz.baseadaptertest;import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;import java.util.List;/*** Created by LGB on 2015/9/9.*/ public class MyAdapter extends BaseAdapter {private List<ItemBean> list;private LayoutInflater inflater;public MyAdapter(Context context, List<ItemBean> list) {this.list = list;inflater = LayoutInflater.from(context);}//該方法返回ListView需要顯示的數據量 @Overridepublic int getCount() {return list.size();}//該方法返回指定索引(position)所對應的數據項 @Overridepublic Object getItem(int position) {return list.get(position);}//該方法返回對應的索引 @Overridepublic long getItemId(int position) {return 0;}//該方法返回每一項所顯示的內容 @Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = inflater.inflate(R.layout.laytou_item, null);}ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_icon);TextView name = (TextView) convertView.findViewById(R.id.tv_name);TextView desc = (TextView) convertView.findViewById(R.id.tv_desc);imageView.setImageResource(list.get(position).ItemImageResid);name.setText(list.get(position).ItemName);desc.setText(list.get(position).Itemdesc);return convertView;} }? ? ? ?我們先判斷要顯示的view是否已經存在,如果不存在,才創建,如果存在,就直接返回,這樣也就避免了多次重復創建。
? ? ? ? ?現在避免了多次創建View對象了,但是每次調用getView的時候,仍然會多次使用findViewById來創建組件,那么有沒有辦法可以避免在這個問題上面浪費資源呢,這里就使用到了view的getTag和setTag,通常我們會創建一個ViewHolder類然后實例化,然后通過setTag的方法將這個ViewHolder對象和View連接起來
???????? 看代碼:
package cn.lixyz.baseadaptertest;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast;import java.util.ArrayList; import java.util.List;public class MainActivity extends AppCompatActivity {List<ItemBean> itemBeanList;ListView listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);itemBeanList = new ArrayList<ItemBean>();for (int i = 0; i < 20; i++) {ItemBean ib = new ItemBean(R.drawable.icon, "標題" + i, "內容" + i);itemBeanList.add(ib);}listView = (ListView) findViewById(R.id.listView);listView.setAdapter(new MyAdapter(this, itemBeanList));listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Toast.makeText(MainActivity.this, "你選擇的是:" + position, Toast.LENGTH_SHORT).show();}});} } MainActivity.java <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"tools:context=".MainActivity"><ListViewandroid:id="@+id/listView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout> activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_icon"android:layout_width="60dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:layout_marginTop="10dp" /><TextViewandroid:id="@+id/tv_name"android:layout_width="match_parent"android:layout_height="35dp"android:layout_marginTop="10dp"android:layout_toEndOf="@+id/iv_icon"android:gravity="center"android:text="標題"android:textSize="25dp" /><TextViewandroid:id="@+id/tv_desc"android:layout_width="match_parent"android:layout_height="25dp"android:layout_below="@+id/tv_name"android:layout_marginLeft="10dp"android:layout_toEndOf="@+id/iv_icon"android:gravity="center"android:text="內容內容內容內容" /></RelativeLayout> layout_item.xml package cn.lixyz.baseadaptertest;/*** Created by LGB on 2015/9/9.*/ public class ItemBean {public int ItemImageResid;public String ItemName;public String Itemdesc;public ItemBean(int ItemImageResid, String ItemName, String Itemdesc) {this.ItemImageResid = ItemImageResid;this.ItemName = ItemName;this.Itemdesc = Itemdesc;} } ItemBean.java package cn.lixyz.baseadaptertest;import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;import java.util.List;/*** Created by LGB on 2015/9/9.*/ public class MyAdapter extends BaseAdapter {private List<ItemBean> list;private LayoutInflater inflater;public MyAdapter(Context context, List<ItemBean> list) {this.list = list;inflater = LayoutInflater.from(context);}//該方法返回ListView需要顯示的數據量 @Overridepublic int getCount() {return list.size();}//該方法返回指定索引(position)所對應的數據項 @Overridepublic Object getItem(int position) {return list.get(position);}//該方法返回對應的索引 @Overridepublic long getItemId(int position) {return position;}//該方法返回每一項所顯示的內容 @Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder vh = null;if (convertView == null) {vh = new ViewHolder();convertView = inflater.inflate(R.layout.laytou_item, null);vh.imageView = (ImageView) convertView.findViewById(R.id.iv_icon);vh.name = (TextView) convertView.findViewById(R.id.tv_name);vh.desc = (TextView) convertView.findViewById(R.id.tv_desc);convertView.setTag(vh);} else {vh = (ViewHolder) convertView.getTag();}vh.imageView.setImageResource(list.get(position).ItemImageResid);vh.name.setText(list.get(position).ItemName);vh.desc.setText(list.get(position).Itemdesc);return convertView;}//創建ViewHolder,避免重復的findViewById操作浪費資源class ViewHolder {public ImageView imageView;public TextView name;public TextView desc;} } MyAdapter.java? ? ? ? ?運行結果是一樣的
? ? ? ? ?在上面的代碼中,我們創建了一個ViewHolder對象,用來保存一個Item的內容,然后使用setTag()將View和ViewHolder對象連接起來,假如convertView不為空的話,直接使用getTag來獲取View對象,然后再給這個對象的屬性賦值(也就是給Item的組件賦值),這樣就充分利用了ListView的緩存機制,避免重復findViewById造成資源的浪費
? ? ? ? ?總結一下使用ListView緩存機制的思路
???????? 1)創建Bean對象,用戶封裝數據(ItemBean)
???????? 2)在構造方法中初始化用戶映射的數據List
???????? 3)創建ViewHolder類,創建布局映射關系
???????? 4)判斷convertView是否為空,如果為空,則創建,并設置tag,如果不為空,則通過getTag來去除ViewHolder
???????? 5)給ViewHolder中的控件設置數據
轉載于:https://www.cnblogs.com/xs104/p/4796423.html
總結
以上是生活随笔為你收集整理的Android笔记(二十五) ListView的缓存机制与BaseAdapter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java Web】Myeclipse下
- 下一篇: android sina oauth2.