Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 手把手教你打造萬能的ListView GridView的適配器

android 手把手教你打造萬能的ListView GridView的適配器

編輯:關於Android編程

我們在開發項目中,listview是最常用的控件,也算是android中控件這塊屬於比較難點的,或容易出現問題的地方,說他難不是說簡單的使用,那個相信大家會,比如結合網絡訪問,異步記載圖片,滑動卡以及嵌套等,今天是寫一篇關於ListView,GridView通用的adapter,而在adapter中getCount,getItem,getItemId,getView要復寫這4個方法,下面看下我們adapter類常寫的方式

布局文件

xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>


item布局


android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:id="@+id/tvContent"
android:layout_width="fill_parent"
android:layout_height="40dp"
/>

MainActivity,class

public class MainActivity extends Activity {
private ListView lv;
private List datas;
private LayoutInflater inflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
inflater = LayoutInflater.from(this);
datas = new ArrayList();
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
datas.add("hello world");
MyAdapter adapter = new MyAdapter();
lv.setAdapter(adapter);
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}


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


@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView==null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item, null);
holder.tvContent = (TextView) convertView.findViewById(R.id.tvContent);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.tvContent.setText(datas.get(position));
return convertView;
}
}

static class ViewHolder{
TextView tvContent;
}
}

在adapter中我們發現其實adapter真正每次實現不一樣的是getView()方法,我們要對其優化封裝,現在想辦法封裝一個通用的adapter,如何抽取呢?其實無非是java面向對象的幾個基本特征:抽象,封裝,繼承,多態,當我們看見一段代碼在每個類中都會出現,那麼我們就最好把這些相同的代碼封裝到一個父類中,而每個類針對不同的業務方法不一樣,就讓其子類去實現,那麼這個時候我們想到了java中的抽象類了,現在就對adapter方法進行簡單的封裝下:

MyBaseAdapter.java

public abstract class MyBaseAdapter extends BaseAdapter {
private List datas;
private Context context;
public MyBaseAdapter(List datas, Context context) {
super();
this.datas = datas;
this.context = context;
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
}

我們發現以後只要繼承此MyBaseAdapter就可以少寫getCount,getItem,getItemId。只要復寫getView()方法即可,這比之前優化進了一下步,現在我們看看getView()方法代碼怎麼寫的

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView==null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item, null);
holder.tvContent = (TextView) convertView.findViewById(R.id.tvContent);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.tvContent.setText(datas.get(position));
return convertView;
}
}

static class ViewHolder{
TextView tvContent;
}

現在發現getView方法中與ViewHoler類綁定在一起,我們知道ViewHolder是通過converetView.setTag()與其綁定,這樣當convertView復用時,就不用findViewById了,因為view的id都封裝在ViewHolder中了,所以針對不同的listview,我們肯定要寫不同的ViewHolder類了,那麼現在想打造一個常用的ViewHolder,繼續優化getView方法,

也就是說,實際上們每個convertView會綁定一個ViewHolder對象,這個viewHolder主要用於幫convertView存儲布局中的控件,那麼ViewHolder類一個是提供setTag方法一個是對外提供一個獲取View對象的方法,根據這2點我們寫一個ViewHolder類出來,

public class ViewHolder {
private View convertView;
public void setTag(){
convertView.setTag(this);
}

public View getView(){

return convertView;
}
}

這個ViewHolder肯定是不能用的,convertView這個變量是從來的,一是通過set方法從外界設置進來,二是通過構造函數傳遞進來,但是如果是通過構造函數對convertView進行初始化,那麼我們可以隨便創建ViewHolder對象了,那麼構造函數就不能對外使用了,這個時候我們就把構造函數做成private,所以我們只要對外提供一種方法就是獲取到ViewHoler,而ViewHolder是和convertView綁定的,如果做緩存的都知道,先看看緩存有沒有,如果沒有就去就去new,在方法內部做一個判斷即可,說了這麼多,把剛才的思路轉換成代碼實現如下:

ViewHolder:

public class ViewHolder {
	    private View mConvertView;  
	    private ViewHolder(Context context, ViewGroup parent, int layoutId, int position)  
	    {  
	        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);  
	        mConvertView.setTag(this);  
	    }  
	    /** 
	     * 獲取一個ViewHolder對象 
	     */  
	    public static ViewHolder get(Context context, View convertView,  
	            ViewGroup parent, int layoutId, int position)  
	    {  
	        if (convertView == null)  
	        {  
	            return new ViewHolder(context, parent, layoutId, position);  
	        }  
	        return (ViewHolder) convertView.getTag();  
	    }  
	    public View getConvertView()  
	    {  
	        return mConvertView;  
	    } 
}

adapter的getView方法如下:

@Override
		public View getView(int position, View convertView, ViewGroup parent) {
		    //實例化一個viewHolder  
	        ViewHolder viewHolder = ViewHolder.get(getApplicationContext(), convertView, parent,  
	                R.layout.item, position);  
	        return viewHolder.getConvertView(); 
		}
此時心中一震竊喜,我很牛逼比,運行跑起來界面空白,我的去啊,趕腳好牛逼,怎麼能讓view設置數據到界面上呢,這又是一個廢鬧細胞的時刻到了,心想一個layout那麼多view,怎麼辦啊,神啊,我突然想到了集合的概念,牛比不,抽煙去,等下繼續寫!集合?List能用麼,不可以為什麼呢?因為每個item上的view,是通過id去尋找的,這麼一說我馬上想到了用Map集合,但是我就不用,我使用android一個自帶的容器,叫做SparseArray這個類

public class ViewHolder {
	    private View mConvertView;  
	    private final SparseArray mViews;
	    private ViewHolder(Context context, ViewGroup parent, int layoutId, int position)  
	    {  
	    	mViews = new SparseArray();
	        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);  
	        mConvertView.setTag(this);  
	    }  
	    /** 
	     * 獲取一個ViewHolder對象 
	     */  
	    public static ViewHolder get(Context context, View convertView,  
	            ViewGroup parent, int layoutId, int position)  
	    {  
	        if (convertView == null)  
	        {  
	            return new ViewHolder(context, parent, layoutId, position);  
	        }  
	        return (ViewHolder) convertView.getTag();  
	    }  
	    public View getConvertView()  
	    {  
	        return mConvertView;  
	    } 
	    /** 
	     * 通過控件的Id獲取對於的控件,如果沒有則加入views 
	     */  
	    public  T $(int viewId)  
	    {  
	          
	        View view = mViews.get(viewId);  
	        if (view == null)  
	        {  
	            view = mConvertView.findViewById(viewId);  
	            mViews.put(viewId, view);  
	        }  
	        return (T) view;  
	    }
}

Adapter中getView方法如下:

class MyAdapter extends MyBaseAdapter {
public MyAdapter(List datas, Context context) {
super(datas, context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//實例化一個viewHolder
ViewHolder viewHolder = ViewHolder.get(getApplicationContext(), convertView, parent,
R.layout.item, position);
TextView tvContent = viewHolder.$(R.id.tvContent);
tvContent.setText(datas.get(position));
return viewHolder.getConvertView();
}
}
}

現在一個adapter中就這幾行代碼了,是不是之前adapter中的代碼要少很多呢,大牛都是寫很少的代碼實現業務,我們在向大牛的方向前行!


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