ListView和RecycleView

1、

ListView的内存优化机制

第一:RecycleBin机制

在ListView里有一个内部类RecycleBin ,RecycleBin 里有一个存储View对象的ArrayList

private ArrayList<View> mCurrentScrap;

当有item滑出了屏幕,itemView会被回收到这个数组里,而有新的item滑入了屏幕时,会从数组里拿到view,这个view做为第二个参数传到了Adapter的getView()方法当中,这样就不用每一次都inflate view了。

@Override  
public View getView(int position, View convertView, ViewGroup parent) {  
    View view;  
    if (convertView == null) {  
        view = LayoutInflater.from(getContext()).inflate(resourceId, null);  
    } else {  
        view = convertView;  
    } 
    return view; 
}

第二:ViewHolder

ListView内部的重用是防止你重复inflate布局,ViewHolder的使用是防止你重复findViewById。

例:

public class MyAdapter extends BaseAdapter {
    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //分离绑定职责
        ViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(resourceId, null);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.bind(getItem(position));
        return convertView;
    }
    class ViewHolder {
        private TextView subView1;
        private TextView subView2;
        ViewHolder(View root){//通过构造方法将子view的查找逻辑搬移到这里
            subView1 = (TextView)root.findViewById(R.id1);
            subView2 = (TextView)root.findViewById(R.id2);
        }
        void bind(ItemData item){
            //绑定逻辑搬移到这里将更加简洁
            subView1.setText(item.text1);
            subView2.setText(item.text2);
        }
    }
}

2、

ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。只不过不使用ViewHolder的话,ListView每次getView的时候都会调用findViewById(int),这将导致ListView性能展示迟缓。而在RecyclerView中使用RecyclerView.ViewHolder则变成了必须,尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    HomeActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position)
            holder.tv.setText(mDatas.get(position));
        }
        @Override
        public int getItemCount(){
            return mDatas.size();
        }

        class MyViewHolder extends ViewHolder{
            TextView tv;
            public MyViewHolder(View view){
                super(view);
                tv = (TextView) view.findViewById(R.id.id_num);
            }
        }
    }

3、

在ListView中如果我们想要在item之间添加间隔符,我们只需要在布局文件中对ListView添加如下属性即可:

 android:divider="@android:color/transparent"
 android:dividerHeight="5dp"

而RecyclerView并没有支持divider这样的属性,但是可以自己定制:
我们可以通过该方法添加分割线:

mRecyclerView.addItemDecoration();

该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类。

4、

我们知道ListView只能在垂直方向上滚动,Android API没有提供ListView在水平方向上面滚动的支持。或许有多种方式实现水平滑动,但是请相信我,ListView并不是设计来做这件事情的。但是RecyclerView相较于ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求,主要如下:

LinearLayoutManager,可以支持水平和竖直方向上滚动的列表。
StaggeredGridLayoutManager,可以支持交叉网格风格的列表,类似于瀑布流或者Pinterest。
GridLayoutManager,支持网格展示,可以水平或者竖直滚动,如展示图片的画廊。

使用如下:

mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

5、

RecyclerView 的item增加、删除的动画是可配置的:RecyclerView.ItemAnimator。

ItemAnimator是一个抽象类,系统为我们提供了一种默认的实现类DefaultItemAnimator。

mRecyclerView.setItemAnimator(new DefaultItemAnimator());

6、

ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。

除了这种方式也可以通过adapter中自己去提供回调,如:

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{

//...
    public interface OnItemClickLitener{
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener){
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position){
        holder.tv.setText(mDatas.get(position));
        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null){
            holder.itemView.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v){
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener() {
                @Override
                public boolean onLongClick(View v){
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });
        }
    }
//...
}

别忘了给item添加一个drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true" android:drawable="@color/color_item_press"></item>
    <item android:drawable="@color/color_item_normal"></item>
</selector>

Activity中去设置监听:

mAdapter.setOnItemClickLitener(new OnItemClickLitener() {

            @Override
            public void onItemClick(View view, int position){
                Toast.makeText(HomeActivity.this, position + " click",
                        Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position){
                Toast.makeText(HomeActivity.this, position + " long click",
                        Toast.LENGTH_SHORT).show();
                        mAdapter.removeData(position);
            }
        });

7、

ListView可以设置选择模式,并添加MultiChoiceModeListener,如下所示:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public boolean onCreateActionMode(ActionMode mode, Menu menu) { ... }
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) { ... }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_item_delete_crime:
        CrimeAdapter adapter = (CrimeAdapter)getListAdapter();
        CrimeLab crimeLab = CrimeLab.get(getActivity());
        for (int i = adapter.getCount() - 1; i >= 0; i--) {
            if (getListView().isItemChecked(i)) {
                crimeLab.deleteCrime(adapter.getItem(i));
            }
      }
    mode.finish();
    adapter.notifyDataSetChanged();
    return true;
    default:
        return false;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { ... }
public void onDestroyActionMode(ActionMode mode) { ... }
});

而RecyclerView则没有此功能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值