浅谈Android中的BaseAdpater

    适配器(Adpater)在Android发开中占有非常重地位,你可以理解它是一个从“数据源”通向“视图控件”的桥梁,下面一张图非常直观的说明了“数据源”、“适配器”、“视图控件”三者间的关系

    Android为我们提供了很多类型的适配器

    从中可以看到,我们之前常用ArrayAdpater、SimpleAdpater等类型的适配器,都是继承于BaseAdapter。BaseAdapter是一个抽象类,我们在使用它的使用它的时候,需要自定义一个类继承它并重写它的一些方法,它的特点是具有较高的灵活性。这里我们还是用ListView来作为今天这个小例子的显示控件。

    1.因为ListView中每一个Item都是一个视图,所以我们先新建一个Item的布局:

item.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="wrap_content">

    <ImageView
        android:id="@+id/image" 
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/ic_launcher"
        />

    <TextView 
        android:id="@+id/title"
        android:text="标题"
        android:textSize="25sp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_toEndOf="@+id/image"        
        />

    <TextView 
        android:id="@+id/text"
        android:text="内容"
        android:textSize="20sp"
        android:gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_toEndOf="@+id/image" 
        android:layout_below="@+id/title"       
        />


</RelativeLayout>
    效果:

    2.创建一个ItemBean类,它抽象了Item中的所有控件对应的数据源
package com.example.baseadapter_test;

/**
 * 将ListView要显示的Item抽象成一个类
 */
public class ItemBean {

    public int Item_ImageResId;
    public String Item_Title;
    public String Item_Text;

    public ItemBean(int Item_ImageResId,String Item_Tilie,String Item_Text) {
        this.Item_ImageResId = Item_ImageResId;
        this.Item_Text = Item_Text;
        this.Item_Title = Item_Tilie;
    }   

}
    3.MainActivity
package com.example.baseadapter_test;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;


public class MainActivity extends Activity {

    private List<ItemBean> itemBeansList = new ArrayList<ItemBean>();

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

        //创建数据源
        for (int i = 0; i < 20; i++) {
            itemBeansList.add(new ItemBean(R.drawable.ic_launcher, "我是标题" + i, "我是内容容" + i));
        }
        //初始化控件
        ListView listView = (ListView)findViewById(R.id.listview);
        //设置适配器
        listView.setAdapter(new MyAdapter(this, itemBeansList));
    }
}
    4.自定义一个MyAdapter类继承BaseAdapter并重写它的一些方法:
package com.example.baseadapter_test;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class MAdpater extends BaseAdapter{

    private List<ItemBean> itemBeansList;

    //LayoutInflater作用是将layout的xml布局文件实例化为View类对象
    private LayoutInflater inflater; 

    public MyAdapter(Context context,List<ItemBean> itemBeansList) {
        this.itemBeansList = itemBeansList;
        inflater = LayoutInflater.from(context);
    }

    /**
     * 返回数据的总数,它的值决定了ListView一共显示多少行
     */
    @Override
    public int getCount() {
        return itemBeansList.size();
    }

    /**
     * 获取数据源中与指定索引对应的数据项
     */
    @Override
    public Object getItem(int position) {
        return itemBeansList.get(position);
    }

    /**
     * 获取在ListView中与指定索引对应的行id
     */
    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 返回每个Item(每一行)的显示内容
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return null;
    }

}
    今天的重点来了~~!!!这里我要重点的说一下public View getView(......)这个方法,它会直接影响到ListView的性能。
    在这之前,我们必须先来了解一下ListView的工作原(摘自http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html):

    1.ListView 针对List中每个item,要求 adapter “给我一个视图” (getView)。

    2.一个新的视图(被创建然后)被返回并显示

    如果我们要显示很多个item,我们肯定不能一直通过重新创建View并返回,因为这样会极大的消耗内存!怎么办呢?Android中有个叫做Recycler的构件,用来缓存视图,下图是他的工作原理:

    (1).如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。


    (2).ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。

    (3).当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图。

    了解了ListView缓存机制后,我们就开始愉快的重写public View getView(......)吧!|_( ̄▽ ̄)_|

重写方式一之“逗比式”:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //将布局文件转化成View对象
        View view = inflater.inflate(R.layout.item, null);
        //在已创建的View查找控件
        ImageView imageView = (ImageView)view.findViewById(R.id.image);
        TextView text = (TextView)view.findViewById(R.id.text);
        TextView title = (TextView)view.findViewById(R.id.title);

        //将数据添加到控件中
        ItemBean bean = itemBeansList.get(position);
        imageView.setImageResource(bean.Item_ImageResId);
        text.setText(bean.Item_Text);
        title.setText(bean.Item_Title);
        return view;
    }
    该方式通过不停的创建View并返回,没有利用到ListView的缓存机制,不但效率低,且非常浪费内存资源,如果你用这钟方式去做开发,我只想说逗比你好!

重写方式二之“普通式”:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //判断convertView是否被缓存(如果已经被创建,就直接使用缓存的convertView,不需要重新创建convertView)
        if(convertView == null){
            //实例化一个布局
            convertView = inflater.inflate(R.layout.item, null);
        }
        ImageView imageView = (ImageView)convertView.findViewById(R.id.image);
        TextView text = (TextView)convertView.findViewById(R.id.text);
        TextView title = (TextView)convertView.findViewById(R.id.title);
        //将数据添加到控件中
        ItemBean bean = itemBeansList.get(position);
        imageView.setImageResource(bean.Item_ImageResId);
        text.setText(bean.Item_Text);
        title.setText(bean.Item_Title);

        return convertView;
    }
    该方式充分利用了ListView的缓存特性,极大提升了ListView的性能。。。美中不足的是太过频繁的使用findViewById(),这是一个非常耗时的操作有木有!!!

重写方式三之“文艺式”:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if(convertView == null){
            convertView = inflater.inflate(R.layout.item, null);
            //将convertView中的控件保存到ViewHolder中
            holder = new ViewHolder();
            holder.imageView = (ImageView)convertView.findViewById(R.id.image);
            holder.text = (TextView)convertView.findViewById(R.id.text);
            holder.title = (TextView)convertView.findViewById(R.id.title);

            //将ViewHolder与convertView进行绑定
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder)convertView.getTag();
        }

        ItemBean bean = itemBeansList.get(position);
        holder.imageView.setImageResource(bean.Item_ImageResId);
        holder.text.setText(bean.Item_Text);
        holder.title.setText(bean.Item_Title);

        return convertView;
    }



static class ViewHolder{    
        public ImageView imageView;
        public TextView text;
        public TextView title;  
    }
    首先我们要知道setTag方法是干什么的,它是给View对象的一个标签,标签可以是任何内容,我们这里把他设置成了一个对象,ViewHolder是一个把item.xml中的所有元素抽象出来的一个类,用了setTag,这个标签就是ViewHolder实例化后对象的一个属性。我们之后对ViewHolder实例化的对象holder的操作,都会因为java的引用机制而一直存活并改变convertView的内容,这样就避免了太过频繁使用findViewById(),而影响ListView的性能。。。简直高大上啊!!!
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值