Android ListView&异步加载的学习(四)——完善ListView滑动效率问题

来源:互联网 发布:linux mkdir 权限 编辑:程序博客网 时间:2024/05/21 15:48

ListView中每一项的Item可能包含一个复杂的内容,而用户在使用时既要加载数据又要滑动ListView,有时会造成ListView的卡顿现象,因此需要进行完善。

考虑到的解决这一问题的思想是:使ListView滑动过程中不加载任何异步任务,停止后再加载可见项

----数据适配器实现整个ListView的滑动事件监听器接口,并实现其中的方法。整体思想:判断当前ListView的滚动状态,如果处于滚动过程中则停止加载可见项,停止滚动后再加载可见项。

----onScroll方法中有两个形参:int   firstVisibleItem第一个可见元素,int   visibleItemCount可见元素长度。因此在适配器类中声明两个int类型的成员变量mStart,mEnd记录开始和终止的可见元素;声明一个String数组记录url地址,通过mStart和mEnd决定加载String数组中哪一段的数据(onScroll方法的作用就在于不断获取当前的第一个和最后一个可见项);在构造方法中初始化该string类型数组,以for循环将图片的url传入静态数组

public NewsAdapter(Context context,List<NewsBean> data){        mList=data;        mInflater=LayoutInflater.from(context);        mImageLoader=new ImageLoader();        URLS=new String[data.size()];        for (int i=0;i<data.size();i++){            URLS[i]=data.get(i).newsIconURL;//图片的url转入静态数组        }    }

----ImageLoader.java文件中添加一个加载从mStart到mEnd的url数据的方法LoadImages,仿照从AsyncTask中读取url的步骤,加载从start到end的所有图片:

public void loadImages(int start,int end){        for(int i=start;i<end;i++){            String url=NewsAdapter.URLS[i];            Bitmap bitmap=getBitmapFromCache(url);            if(bitmap==null) {                NewsAsyncTask task=new NewsAsyncTask(url);                task.execute(url);                mTask.add(task);            }else{                ImageView imageView= (ImageView) mListView.findViewWithTag(url);                imageView.setImageBitmap(bitmap);            }        }    }

但此时不是再向整个ImageView中读取url,而是向指定的起始和终止位置之间读取数据,因此NewsAsyncTask(imageView, url).execute(url);以及imageView.setImageBitmap(bitmap);语句中向imageView传递url是不合适的,用ListView就能找到ImageView。需要给ImageLoader声明新的成员变量private ListView mListView;和private Set<NewsAsyncTask> mTask;并在构造方法中进行初始化:mListView=listview;   mTask=new HashSet<>();;在onPostExecute方法中通过找到的ImageView去设置bitmap;设置完bitmap之后代表这个Task已经结束了,需要在集合中remove掉这个AsyncTask。

class NewsAsyncTask extends AsyncTask<String,Void,Bitmap>{    //    private ImageView mImageView;        private String mUrl;        public NewsAsyncTask(String url){            /*mImageView = imageView;*/            mUrl=url;        }        @Override        protected Bitmap doInBackground(String... params) {            Bitmap bitmap=getBitmapFromUrl(params[0]);            if (bitmap!=null){                addBitmapToCache(params[0], bitmap);            }            return bitmap;        }        @Override        protected void onPostExecute(Bitmap bitmap) {//将Bitmap传递给ImageView            super.onPostExecute(bitmap);            ImageView imageView= (ImageView) mListView.findViewWithTag(mUrl);            if (imageView!=null&&bitmap!=null){                imageView.setImageBitmap(bitmap);            }            mTask.remove(this);        }    }

----**不要忘记注册接口——注册对应的事件:listView.setOnScrollListener(this);

以上,实现了将显示图片的控制权从getView转换到了滑动监听事件。但是发现初次启动程序时图片是不加载的,想到的原因在于,在第一次启动ListView的时候是默认ListView的状态没有发生改变的,而onScrollStateChanged方法在初次运行时不会自动调用。要进行完善。

解决问题的思路:虽然onScrollStateChanged方法在初次运行时不会自动调用,,但是onScroll方法会调用,因此在适配器类中增加一个成员变量Flag来判断是否是第一次启动,并在初始化时赋值为true——private boolean mFirstIn;    mFirstIn=true;;在onScroll方法中增加判断语句判断是否是第一次加载且屏幕上的item大于0,若是则将start和end传递给loadImages()方法,人为的显示第一屏的数据;之后将flag设置为false,此后不会再走这一步的逻辑,通过onScrollStateChanged方法来加载图片

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        //firstVisibleItem第一个可见元素,visibleItemCount可见元素长度        mStart=firstVisibleItem;        mEnd=firstVisibleItem+visibleItemCount;        if (mFirstIn&&visibleItemCount>0){            mImageLoader.loadImages(mStart,mEnd);            mFirstIn=false;        }    }
以上完成了对ListView加载图片执行效率的全部优化。


总结:此例完成的是一级缓存——将加载内容缓存到内存,其余的还有将内容缓存到硬盘等,可以使用DiskLruCache这个第三方的类来实现“二级缓存”。异步加载不仅是获取网络资源,可以将任何耗时操作都看成异步加载,所有通过耗时操作获取的结果都可以通过缓存来提高效率。但是Cache也存在缺点——不能保证数据使实时的,所以在realtime需求高的应用中不能使用缓存。而对于本地资源,很少用到缓存。

0 0