美文网首页
Listview,Recycleview以及Adapter优化

Listview,Recycleview以及Adapter优化

作者: cifer_xiao | 来源:发表于2017-07-04 14:24 被阅读0次

    一.Listview和优化

    首先

    listview继承自AbsListView,(Gridview也继承自这个类,有机会再说),

    Screenshot from 2017-07-04 10:34:02.png

    (源码本人今天眼睛不舒服日后再看- -)

    然后

    关于Adapter。先说控件,是用来交互和展示数据的,但是由于listview需要展示的数据量过大,所以需要adapter提供数据,顾名思义,Adapter是适配器的意思,它在ListView和数据源之间起到了一个桥梁的作用,ListView并不会直接和数据源打交道,而是会借助Adapter这个桥梁来去访问真正的数据源,与之前不同的是,Adapter的接口都是统一的,因此ListView不用再去担心任何适配方面的问题。而Adapter又是一个接口(interface),它可以去实现各种各样的子类,每个子类都能通过自己的逻辑来去完成特定的功能,以及与特定数据源的适配操作。而adapter作为复杂数据的展示的转换载体,所以各种Adapter只不过是转换的方式和能力不一样而已。如图:

    Screenshot from 2017-07-04 10:26:23.png

    ArrayAdapter

    ArrayAdapter是一个绑定View到一组对象的通用类。默认情况下,ArrayAdapter绑定每个对象的toString值到在layout中预先定义的TextView控件上。可变通的,构造函数允许你使用更加复杂的layout或者通过重写getView方法来扩展类从而使用TextView的替代物(如ImageView或嵌套的layout)。

    SimpleCursorAdapter

    SimpleCursorAdapter绑定View到Content Provider查询返回的游标上。指定一个XML layout定义,然后将数据集中的每一列的值绑定到layout中的一个View上。

    Adapter的getView方法

    个人觉得这个方法在重写adapter的时候上镜率很高,所以具体分析下。

    public View getView(int position, View convertView, ViewGroup parent) {}
    

    getview方法用来刷新listview,在每一次item从屏幕外滑进屏幕内的时候,或者程序刚开始的时候创建第一屏item的时候都会调用这个方法。
    position是指当前dataset的位置,通过getCount和getItem来使用。如果list向下滑动的话那么就是最低端的item的位置,如果是向上滑动的话那就是最上端的item的位置。convertView是指可以重用的视图,即刚刚出队的视图。parent应该就是list。还有一个return:
    A View corresponding to the data at the specified position.
    具体使用看情况,完毕。

    最后

    关于listview的优化问题。菜鸟写法:

    public class CustomAdapter extends ArrayAdapter {
        private int dataid;
        public CustomAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
            super(context, resource, textViewResourceId);
            dataid=resource;
        }
        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            View view= LayoutInflater.from(getContext()).inflate(dataid,parent,false);
            TextView textView=(TextView)view.findViewById(...);
            ImageView imageView=(ImageView)view.findViewById(...);
            return view;
        }
    }
    

    上述方法效率低在:getview方法中每次都把布局重新加载了一遍。而且可以看到上述方法中有个convertview一直闲着,他是用来把之前加载好的布局先进行缓存,以便之后重用。所以优化getview如下:

    @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            View view;
            if(convertView==null){
            view= LayoutInflater.from(getContext()).inflate(dataid,parent,false);
            }else{
                view=convertView;
            }
            TextView textView=(TextView)view.findViewById(...);
            ImageView imageView=(ImageView)view.findViewById(...);
            return view;
        }
    

    上面这个方法虽然不会在重复加载布局,但是有一个叫做findviewbyid的方法一直重复使用。这个方法会自上而下的遍历控件树,十分消耗内存,所以再借助一个viewholder来优化性能。viewholder类需要自己进行定义(内部类):

    class ViewHolder{
    private Textview textview;
    private Imageview imageview;
    }
    

    具体如下:

    public view getView(int position,View convertview,ViewGroup parent){
    View view;
    ViewHolder viewholder;
    if(convertview== null){
    view=LayoutInflater.from(getContext()).inflate(dataid,parent,false);
    viewholder = new ViewHolder();
    viewholder.textview=(Textview)view.findviewbyId(...);
    viewholder.imageview=(Imageview)view.findviewbyId(...);
    view.setTag(viewholder);     //将viewholder存储在view中
    }else{
    view = convertview;
    viewholder= (ViewHolder)view.getTag();  //重新获取ViewHolder
    }
    return view;
    }
    

    view的setTag和getTag方法,存储和获取ViewHolder,不用每次重新加载都去调用findviewbyid方法。后续关于listiew的运用有缘再更新,接下来学习recyclerview.

    二.Recyclerview

    首先

    recyclerview定义在了support库中,想用的话要先在build.gradle中添加依赖库。
    dependencies{
    ...
    compile 'com.android.support:recyclerview-v7:25.2.1'
    ...
    }

    然后

    关于使用。基本和listview差不多,找几个方法说一哈:

    • ItemDecoration:添加item之间的分割线。
      addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
      也可以自己在style和drawable中定义分割线的颜色,这里先过。
    • LayoutManager :这是一个抽象类,系统提供了3个实现类:
      1 LinearLayoutManager 现行管理器,支持横向、纵向。
      2 GridLayoutManager 网格布局管理器。
      3 StaggeredGridLayoutManager 瀑布就式布局管理器。
    • ItemAnimator: 设置item动画
      mRecyclerView.setItemAnimator(new DefaultItemAnimator());有机会用到再详细学习。

    最后

    在下学习的是第二行代码里面有详细介绍了横向滚动和瀑布式布局,在此整理下。

    • 横向布局就是利用了LinearLayoutManager实现:
    LinearLayoutManager llm=new LinearLayoutManager(this);
    llm.setorientation(LinearLayoutManager.HORIZONTAL);
    recycleview.setLayoutManager(llm);
    
    • StaggeredGridLayoutManager 瀑布就式布局管理器:
    StaggeredGridLayoutManager mmm=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
    ...
    

    书中运用了一个Random方法看上去效果很明显这里就不赘述了。

    最后

    关于瀑布式布局的点击事件,重写了Adapter extends RecycleView.Adapter<...ViewHolder>,在ViewHolder中添加view的变量保存最外层布局实例,然后在onCreatedViewHolder()方法中添加点击时间就好了。具体项目以后做到再单独贴,书上的就不办过来了。

    补充:

    Recyclerview实际上是一个自定义的Viewgroup,子视图chilid对应着每一个RecyclerView的item。其中关于ItemDecoration类,可以优化它的视觉效果,具体的明天看心情写。

    关于Recyclerview的界面跳转:

    • 由于Recyclerview是没有onclicklistener的,所以跳转的时候写在了adapter的onCreateViewHolder中,本人用的是intent的隐式:
     <activity android:name=".SecondActivity"
                android:theme="@style/AppTheme.Zero">
                <intent-filter>
                    <action android:name="android.intent.action.ACTION_START" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
    
      @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent,int viewtype){
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.car_item,parent,false);
            final ViewHolder viewHolder=new ViewHolder(view);
            viewHolder.carview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position=viewHolder.getAdapterPosition();
                    Car car=mcarList.get(position);
                    Toast.makeText(view.getContext(),"你点击了"+car.getCarname()
                    ,Toast.LENGTH_SHORT).show();
                    Intent intent=new Intent("android.intent.action.ACTION_START");
                    view.getContext().startActivity(intent);
                }
            });
    

    因为心情原因就不多说了直接看代码。

    以前看书的时候没啥感觉看过就过了再复习一遍觉得印象更加深刻了,就先酱紫。

    相关文章

      网友评论

          本文标题:Listview,Recycleview以及Adapter优化

          本文链接:https://www.haomeiwen.com/subject/xhmthxtx.html