Android ListView适配器BaseAdapter

ListView作为Android的一个高级控件,使用的频率是非常高的,它不像一些简单的控件直接在xml文件中设置各项参数就能达到预期的结果,而需要一个中间件的支持,这个中间件就是adapter。

一个简单的关系图说明ListView的使用层次关系:
层次关系
上图中,向下是set和use的关系,向上是控制关系,即ListView使用adapter,adapter使用数据源data,data控制adapter的数据源,adapter控制ListView的逻辑功能。

这里对于新手来说还是比较难理解的,显示点东西比较容易,但是一但嵌套其它可操作的控件就产生疑惑了:如何判定哪个控件被点击,哪个控件状态改变了都成了问题。这里我们一并说明!

首先是我们的MainActivity.java

public class MainActivity extends Activity {

    ListView main_list;
    MyAdapter adapter;

    List<Info> datalist;

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

        main_list=(ListView)findViewById(R.id.main_list);
        datalist=new ArrayList<Info>();

        datalist.add(new Info("我是第一个"));
        datalist.add(new Info("我是第二个"));
        datalist.add(new Info("我是第三个"));
        datalist.add(new Info("我是第四个"));
        datalist.add(new Info("我是第五个"));

        adapter=new MyAdapter(this,datalist);

        main_list.setAdapter(adapter);
    }
}

很简单的一个activity,其中的Info类是我们的数据承接bean,代码是:

public class Info {

    String text;

    public Info(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

最后是我们的adapter:

public class MyAdapter extends BaseAdapter{

    private Context c;
    private List<Info> datalist;
    private LayoutInflater inflater;

    //构造,传入我们Activity的this和数据源datalist
    public MyAdapter(Context c,List<Info> datalist)
    {
        this.c=c;
        this.datalist=datalist;
        this.inflater=LayoutInflater.from(c);
    }

    //以下三个方法是adapter自动调用的,但是需要我们对它进行简单修改,照猫画虎就行
    @Override
    public int getCount() {
        return datalist.size();
    }

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

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

    //adapter的核心方法,需要仔细研究
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        final int pos=position;

        //这里的if-else是基于ListView的缓存机制编写的,使用一个ViewHolder来承接我们ListView中每一个小项中的控件。注意findViewById是比较耗时的操作,这样做可以增加重用,避免多次调用耗时操作
        ViewHolder holder=null;
        if(convertView==null)
        {
            convertView=inflater.inflate(R.layout.item, null);
            holder=new ViewHolder();
            holder.cb_check=(CheckBox) convertView.findViewById(R.id.cb_check);
            holder.tv_text=(TextView) convertView.findViewById(R.id.tv_text);

            convertView.setTag(holder);
        }else{
            holder=(ViewHolder) convertView.getTag();
        }

        holder.tv_text.setText(datalist.get(position).getText()+"--"+position);

        //间隔勾选CheckBox而已,没什么技术含量
        holder.cb_check.setChecked(position%2==0?true:false);

        //这里解决我们在一个ListView小项中嵌套可操作控件的问题,实际每次点击都是可以获得当前你点击的位置position的,
        holder.cb_check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked)
                {
                    Toast.makeText(c, datalist.get(pos).getText()+" 勾上了", Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(c, datalist.get(pos).getText()+" 取消了", Toast.LENGTH_SHORT).show();
                }
            }
        });

        //为ListView的item设置了点击事件的监听
        convertView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(c, datalist.get(pos).getText(), Toast.LENGTH_SHORT).show();
            }
        });

        return convertView;
    }

    class ViewHolder{
        TextView tv_text;
        CheckBox cb_check;
    }   
}

!!跪求注意的部分:
我们的adapter继承BaseAdapter,这里我们需要实现这个抽象类的几个方法,注释中有详细的说明。再次强调一下:在我们手指滑动屏幕上的ListView时,getView方法会不断执行,如果在里面加一个log输出,一滑动产生n多输出。
而且这个方法是线性执行的,前一个getView执行完后才会执行下一个getView,这也就解释了当我们数据量比较多时,滑动出现卡顿的问题,因为getView的执行出现了高耗时,绘制一个item需要过多的时间。

另外,我们完全可以在这个adapter中维护一个列表,这个列表存储每个checkbox的状态,拿到了每个checkbox 的状态就可以对ListView中的数据进行批量修改(文件的批量删除就是这样实现的!)。

最后贴上xml的布局代码:

activity_main.xml

<RelativeLayout 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"
    tools:context="${relativePackage}.${activityClass}" >

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

</RelativeLayout>

item.xml

<?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="20dp"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <CheckBox
        android:id="@+id/cb_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="CheckBox" />

</LinearLayout>

ok,就到这里~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值