BaseAdapter -- convertView回收机制与动态控件响应

BaseAdapter – convertView回收机制与动态控件响应

一,ConvertView回收机制

工作原理:

  1. ListView针对List中每个item,要求adapter“给我一个试图”(getView)
  2. 一个新试图被返回并显示

Android为此缓存了视图,Android有一个叫做Recycler的构件,下图是它的工作原理。

img

ListView先请求一个item1视图(getView)并且请求其他屏幕可见的视图,此时convertView是空(null)。

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

二,实例

在这里插入图片描述

public class MainActivity extends AppCompatActivity {

    private List<String> infos = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        ListView listView = findViewById(R.id.liseView);
        MyAdapter adapter = new MyAdapter(this,infos);
        listView.setAdapter(adapter);
    }
    
    public void initData(){
        for (int i = 0 ;i<50;i++){
            infos.add("第"+(i+1)+"信息");
        }
    }
}

public class MyAdapter extends BaseAdapter {

    private LayoutInflater inflater;
    private List<String> infos;
    public MyAdapter(Context context,List<String> infos) {
        inflater = LayoutInflater.from(context);
        this.infos = infos;
    }

    @Override
    public int getCount() {
        return infos.size();
    }

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

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.layout_item, parent, false);
        holder.info = convertView.findViewById(R.id.info);
        holder.attention = convertView.findViewById(R.id.attention);
        holder.info.setText(infos.get(position));
       final  TextView attention = holder.attention;
        holder.attention.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { 
                attention.setTextColor(Color.RED);
            }
        });

        return convertView;
    }
    
    static class ViewHolder{
        TextView info;
        TextView attention;
    }
}

手机初始化是这样子的:

在这里插入图片描述

根据上面的理论,在初始化时,整个屏幕可以放下三个item,所以会创建三个全新的convertView。当手指向上滑,出现第四个item时,就会回收第一个item的convertView给第四个。

在这里插入图片描述

可以看到,前四个convertView为null,当地五个item出现时,此时由于第一个item肯定已经滚出屏幕,所以将其重新传给即将出现的item5使用。回到上面的代码,我们为“关注”写了一个点击事件,当点击"关注"的时候,字体会变红,如下:

点击关注

在这里插入图片描述

手指向上滑再滑回来

在这里插入图片描述

问题出现,当滑回来的时候,”关注“不再红了

问题出现在代码上:

 holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.layout_item, parent, false);
            holder.info = convertView.findViewById(R.id.info);
            holder.attention = convertView.findViewById(R.id.attention);

每次运行getView 获取当前item时,都会重新new一个ViewHolder与R.layout.item绑定,也就是说,每次都会产生一个新布局赋值给convertView让其显示。上面讲过,Android会将回收过来的convertView返回给即将显示的getView使用,以节约资源。而这里我们每次都新建一个布局赋值给convertView,由于每次都是新建布局,所以item1

被重新拉回来显示的时候,由于是重新创建的布局,当然是初始状态。

改进

public class MainActivity extends AppCompatActivity {

    private List<String> infos = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        ListView listView = findViewById(R.id.liseView);
        MyAdapter adapter = new MyAdapter(this,infos);
        listView.setAdapter(adapter);
    }

    public void initData(){
        for (int i = 0 ;i<50;i++){
            infos.add("第"+(i+1)+"信息");
        }
    }
}



public class MyAdapter extends BaseAdapter {

    private LayoutInflater inflater;
    private List<String> infos;
    public MyAdapter(Context context,List<String> infos) {
        inflater = LayoutInflater.from(context);
        this.infos = infos;
    }

    @Override
    public int getCount() {
        return infos.size();
    }

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

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        System.out.println("position:"+position+"   convertView:"+convertView);
        ViewHolder holder = null;
        if (convertView==null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.layout_item, parent, false);
            holder.info = convertView.findViewById(R.id.info);
            holder.attention = convertView.findViewById(R.id.attention);
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.info.setText(infos.get(position));
       final  TextView attention = holder.attention;
        holder.attention.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                attention.setTextColor(Color.RED);
            }
        });

        return convertView;
    }

    static class ViewHolder{
        TextView info;
        TextView attention;
    }
}

点击

在这里插入图片描述

滑上去再滑回来

在这里插入图片描述

再往下拉

在这里插入图片描述

问题出现在第三张图,明明没有点击item5,但是关注是红色的

这是因为item5用的是item1回收来的convertView,而item1中的关注是红色的,所以只要回收机制在,我们就没有办法改变从item1回收来的convertView的图片布局。

理解了这个问题,解决办法如下:

首先申请一个ArrayList attentionArr变量,保存用户点击“关注”的item的position,然后在绘制当前item时,根据这个position是否在attentionArr里来判断是不是将关注重新变红。

代码如下:

public View getView(final int position, View convertView, ViewGroup parent) {
        System.out.println("position:"+position+"   convertView:"+convertView);
        ViewHolder holder = null;
        if (convertView==null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.layout_item, parent, false);
            holder.info = convertView.findViewById(R.id.info);
            holder.attention = convertView.findViewById(R.id.attention);
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.info.setText(infos.get(position));
       final  TextView attention = holder.attention;
       if (attentionArr.contains(position)){
           attention.setTextColor(Color.RED);
       }else{
           attention.setTextColor(Color.BLACK);
       }
        holder.attention.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    attention.setTextColor(Color.RED);
                  	attentionArr.add(position);
                
            }
        });

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值