zoukankan      html  css  js  c++  java
  • Android RecyclerView使用 及 滑动时加载图片优化方案

    1、控制线程数量 + 数据分页加载2、重写onScrollStateChanged方法

    这个我们后面再谈,下面先来看看RecyclerView控件的使用及我们为什么选择使用它

    RecyclerView的使用

    RecyclerView 位于package android.support.v7.widget; 包下,直接继承了android.view.ViewGroup,是Android中新添加的一个用来取代ListView的滑动控件,其灵活性与可替代性比ListView更优秀,运行原理与ListView类似,都是通过维护少量的View可展示大量的数据集。

    总结其优点:

    一、标准化了ViewHolder,使用Adapter适配器时,面向ViewHolder而不是单纯的View,直接把ViewHolder的实现封装起来,用户只要实现自己的ViewHolder就可以了,该组件会自动帮你回收并复用每一个item。不但变得更精简,也变得更加容易使用,而且更容易组合设计出自己需要的滑动布局。二、将Layout抽象成了一个LayoutManager,RecyclerView不负责子View的布局,而是通过使用LayoutManager来实现不同的布局效果,如使用LinearLayoutManager来指定方向,其默认是垂直,也可以设置为水平,当然你也可以自己来定义。

    我们来看看官方给出的示例:

    1.MyActivity.java

     public class MyActivity extends Activity {  
        private RecyclerView mRecyclerView;  
        private RecyclerView.Adapter mAdapter;  
        private RecyclerView.LayoutManager mLayoutManager;  
       
        @Override 
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.my_activity);  
            mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);  
       
            // improve performance if you know that changes in content do not change the size of the RecyclerView  
           //如果确定每个item的内容不会改变RecyclerView的大小,设置这个选项可以提高性能
            mRecyclerView.setHasFixedSize(true);  
       
            // use a linear layout manager  
           //创建默认的线性LayoutManager
            mLayoutManager = new LinearLayoutManager(this);  
            mRecyclerView.setLayoutManager(mLayoutManager);  
       
            // specify an adapter (see also next example)  
           //设置Adapter
            mAdapter = new MyAdapter(myDataset);  
            mRecyclerView.setAdapter(mAdapter);  
        }  
        ...  
    }

    LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。提供默认的动画效果,你也可以定义你自己的LayoutManager和添加删除动画。在回收或重用一个View时,LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法。

    2.MyAdapter

     public class MyAdapter extends RecyclerView.Adapter<myadapter.viewholder> {  
        private String[] mDataset;  
       
        // Provide a reference to the type of views that you are using (custom viewholder)  
        //自定义的ViewHolder,持有每个Item的的所有界面元素
        public static class ViewHolder extends RecyclerView.ViewHolder {  
            public TextView mTextView;  
            public ViewHolder(TextView v) {  
                super(v);  
                mTextView = v;  
            }  
        }  
       
        // Provide a suitable constructor (depends on the kind of dataset)  
        public MyAdapter(String[] myDataset) {  
            mDataset = myDataset;  
        }  
       
        // Create new views (invoked by the layout manager)  
       //创建新View,被LayoutManager调用
        @Override 
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,  
                                                       int viewType) {  
            // create a new view  
            View v = LayoutInflater.from(parent.getContext())  
                                   .inflate(R.layout.my_text_view, parent, false);  
            // set the view's size, margins, paddings and layout parameters  
            ...  
            ViewHolder vh = new ViewHolder(v);  
            return vh;  
        }  
       
        // Replace the contents of a view (invoked by the layout manager)  
       //将数据与界面进行绑定
        @Override 
        public void onBindViewHolder(ViewHolder holder, int position) {  
            // - get element from your dataset at this position  
            // - replace the contents of the view with that element  
            holder.mTextView.setText(mDataset[position]);  
       
        }  
       
        // Return the size of your dataset (invoked by the layout manager)  
        //这个就不解释了
        @Override 
        public int getItemCount() {  
            return mDataset.length;  
        }  
    }

    Adapter:在使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器,作用是将数据与每一个item的界面进行绑定。

    滑动时图片优化方案描述

    1、控制线程数量 + 数据分页加载

    我们在使用滑动控件呈现图片数据时,显然都会在getView方法里创建新的线程去异步加载图片,不可能有一百条或上千条数据一口气全部塞过来吧(当然你要这么干也是可以的),那么根据项目需求必然会进行分页加载,咱一页显示的item条数也别太夸张就好。而且,当我们点击屏幕快速向下滑动时,每个Item都会调用getView一次,必然会创建出很多线程去加载图片的URL资源,控制好线程的数量,加个线程池就非常有必要了。为了避免OOM导致FC,注意图片需要缓存,因为从内存中读取图片资源是非常快的。

    2、重写onScrollStateChanged方法

    这种方案用的也很普遍,相信只要细心观察,就会发现类似微博、Facebook、或者一些图片壁纸类的APP,在滑动时未加载的图片是不会立刻加载呈现的,只有当滑动停止后才会加载,这里需要注意一点的是,只加载当前屏幕内的图片。这么一说可能有童鞋就明白了。我们可以通过继承RecyclerView去自定义一个滑动控件,通过继承OnScrollListener后重写其 onScrolled方法 和 onScrollStateChanged 等方法来做相应处理。

    例如:

    private class AutoLoadScrollListener extends OnScrollListener {   
           //......
           public void onScrollStateChanged(RecyclerView recyclerView, int newState){
           }
    }

    我们通过 extends OnScrollListener 并且 @Override 其 onScrollStateChanged 方法,通过判断state来处理,此处对其滚动的状态newState做一个说明,方面大家了解学习,分别有3个状态,即 0 - 1 - 2:

    状态为0时:当前屏幕停止滚动;

    状态为1时:屏幕在滚动 且 用户仍在触碰或手指还在屏幕上;

    状态为2时:随用户的操作,屏幕上产生的惯性滑动;

    先来瞄瞄activity_main.xml布局文件:

    <?xml version=1.0 encoding=utf-8?>
    <Linearlayout
      android:fitssystemwindows="true"
      android:layout_height="match_parent"
      android:layout_width="match_parent"
       android:orientation="vertical"
       xmlns:android="https://schemas.android.com/apk/res/android"> <Relativelayout
          android:background="#00F1A0"
          android:id="@+id/layout_titlebar"
          android:layout_height="48dp"
          android:layout_width="match_parent">
          <Textview
          
    android:id="@+id/text_title"
           android:layout_height="match_parent"
       android:layout_width="match_parent"
           android:gravity="center"
           android:text="好慌~"
           android:textcolor="@android:color/white"
          android:textsize="16dp"/>
      </Relativelayout>
     
        <Framelayout 
          android:id="@+id/frame_container"
          android:layout_height="match_parent"
          android:layout_width="match_parent"/>
    </Linearlayout>

    很简单,用了一个Fragment而已,再来看看主Fragment的布局:

    <?xml version=1.0 encoding=utf-8?>
    <Framelayout
       android:background="@android:color/white"
       android:layout_height="match_parent"
    android:layout_width="match_parent"
    xmlns:android="https://schemas.android.com/apk/res/android">
    <android.support.v4.widget.SwipeRefreshLayout
          android:layout_height="match_parent" 
          android:layout_width="match_parent">
        <org.gaochun.view.AutoLoadRecyclerView
          android:id="@+id/recycler_view"
          android:layout_height="match_parent"
          android:layout_width="match_parent"
        android:scrollbars="vertical"> </org.gaochun.view.AutoLoadRecyclerView>
     </android.support.v4.widget.SwipeRefreshLayout> </Framelayout>
    package org.gaochun.myapplication;
     
    import java.util.ArrayList;
    import java.util.List;
     
    /**
     * Created by gao_chun on 2015/9/18.
     */
    public class ImageUrl {
     
        public static List<string> imageList(){
     
            List<string> mUrls = new ArrayList<string>();
            mUrls.add(https://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg);
            mUrls.add(https://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg);
            mUrls.add(https://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg);
            mUrls.add(https://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg);
            mUrls.add(https://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg);
            mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg);
            mUrls.add(https://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg);
            mUrls.add(https://www.huabian.com/uploadfile/2014/1202/20141202025659854.jpg);
            mUrls.add(https://www.huabian.com/uploadfile/2014/1202/20141202025700989.jpg);
            mUrls.add(https://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg);
            mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg);
            mUrls.add(https://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg);
            mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg);
            mUrls.add(https://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg);
            mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg);
            mUrls.add(https://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg);
            mUrls.add(https://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg);
            mUrls.add(https://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg);
            mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg);
            mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg);
            mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg);
            mUrls.add(https://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg);
            return mUrls;
        }
    }

    下面来看看主要的类AutoLoadRecyclerView,其实这个类也很简单:

    public class AutoLoadRecyclerView extends RecyclerView implements LoadFinishCallBack {
     
        private onLoadMoreListener loadMoreListener;    //加载更多回调
        private boolean isLoadingMore;                  //是否加载更多
     
        public AutoLoadRecyclerView(Context context) {
            this(context, null);
        }
     
        public AutoLoadRecyclerView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
     
        public AutoLoadRecyclerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
     
            isLoadingMore = false;  //默认无需加载更多
            setOnScrollListener(new AutoLoadScrollListener(null, true, true));
        }
     
        /**
         * 配置显示图片,需要设置这几个参数,快速滑动时,暂停图片加载
         *
         * @param imageLoader   ImageLoader实例对象
         * @param pauseOnScroll
         * @param pauseOnFling
         */
        public void setOnPauseListenerParams(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {
     
            setOnScrollListener(new AutoLoadScrollListener(imageLoader, pauseOnScroll, pauseOnFling));
     
        }
     
        public void setLoadMoreListener(onLoadMoreListener loadMoreListener) {
            this.loadMoreListener = loadMoreListener;
        }
     
        @Override
        public void loadFinish(Object obj) {
            isLoadingMore = false;
        }
     
     
        //加载更多的回调接口
        public interface onLoadMoreListener {
            void loadMore();
        }
     
     
        /**
         * 滑动自动加载监听器
         */
        private class AutoLoadScrollListener extends OnScrollListener {
     
            private ImageLoader imageLoader;
            private final boolean pauseOnScroll;
            private final boolean pauseOnFling;
     
            public AutoLoadScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {
                super();
                this.pauseOnScroll = pauseOnScroll;
                this.pauseOnFling = pauseOnFling;
                this.imageLoader = imageLoader;
            }
     
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
     
                //由于GridLayoutManager是LinearLayoutManager子类,所以也适用
                if (getLayoutManager() instanceof LinearLayoutManager) {
                    int lastVisibleItem = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();
                    int totalItemCount = AutoLoadRecyclerView.this.getAdapter().getItemCount();
     
                    //有回调接口,且不是加载状态,且计算后剩下2个item,且处于向下滑动,则自动加载
                    if (loadMoreListener != null && !isLoadingMore && lastVisibleItem >= totalItemCount -
                            2 && dy > 0) {
                        loadMoreListener.loadMore();
                        isLoadingMore = true;
                    }
                }
            }
     
            //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;由于用户的操作,屏幕产生惯性滑动时为2
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
     
                //根据newState状态做处理
                if (imageLoader != null) {
                    switch (newState) {
                        case 0:
                            imageLoader.resume();
                            break;
     
                        case 1:
                            if (pauseOnScroll) {
                                imageLoader.pause();
                            } else {
                                imageLoader.resume();
                            }
                            break;
     
                        case 2:
                            if (pauseOnFling) {
                                imageLoader.pause();
                            } else {
                                imageLoader.resume();
                            }
                            break;
                    }
                }
            }
        }

    也就是说,我们通过定义了一个 setOnPauseListenerParams 方法去设置滑动监听事件setOnScrollListener,并通过定义内部类AutoLoadScrollListener去@Override相关方法并做相应的处理。

  • 相关阅读:
    HDU5269 字典树
    HDU1664 BFS + 数论 + 剪枝
    HDU1429 BFS + 状态压缩
    HDU1075 字典树 + 字符串映射
    HDU1247 字典树
    UVa 10256(凸包、线段交、点在多边形内)
    UVa 10652(旋转、凸包、多边形面积)
    牛客练习赛43D(贪心)
    牛客练习赛43F(推式子)
    Codeforces 1161B(判断旋转对称)
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/8125381.html
Copyright © 2011-2022 走看看