• Android异步载入学习笔记之四:利用缓存优化网络载入图片及ListView载入优化


           假设不做不论什么处理。直接用网络载入图片在网速快的情况下可能没什么不好的感觉。可是假设使用移动流量或是网络不好的时候。问题就来了,要么用户会抱怨流量使用太多。要么抱怨图片载入太慢。如论从哪个角度出发,都不是好的体验!

    要提高用户体验,我们就要使用缓存。Android中数据缓存的方式有非常多,相关介绍的文章也比較多。比方http://blog.csdn.net/dahuaishu2010_/article/details/17093139http://www.jb51.net/article/38162.htm等。今天学习是是Lru缓存。

     Lru(Least Recently Used)近期最少使用算法,即是在一定条件下LRU缓存是把近期最少使用的数据移除。让给最新读取的数据。而往往最常读取的,也是读取次数最多的。所以。利用LRU缓存,我们可以提高应用的效率及用户体验度。Andorid本身提供了LruCache类来实现这个缓存算法 。

    在ImageLoader中利用LruCache缓存:

    public class ImageLoader {
    private LruCache<String, Bitmap> mCaches;// 创建LruCache对象
    private ImageView mImageView;
    private ListView listView;
    private Set<ImageAsyncTask> mTask;


    @SuppressLint("NewApi")
    public ImageLoader(ListView listView) {
    this.listView = listView;
    mTask = new HashSet<ImageAsyncTask>();
    int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取最大可用内存
    int cacheSize = maxMemory / 8;// 设置缓存数据的最大占用内存量为最大值1/8
    mCaches = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap value) {
    return value.getByteCount();// 每次存入缓存的时候调用,返回bitmap的大小
    }
    };
    }


    @SuppressLint("NewApi")
    /**
    * 添加缓存数据。添加前推断数据是否存在
    * @description:
    * @author ldm
    * @date 2015-8-11 下午7:51:04
    */
    public void setLruCaches(String url, Bitmap bitmap) {
    if (getLruCaches(url) == null) {// 假设缓存中不存在url相应的Bitmap。则把bitmap增加mCaches
    mCaches.put(url, bitmap);
    }
    }


    /**
    * 从缓存中获取数据
    * @description:
    * @author ldm
    * @date 2015-8-11 下午7:51:22
    */
    @SuppressLint("NewApi")
    public Bitmap getLruCaches(String url) {
    return mCaches.get(url);// 通过url获取缓存中相应的bitmap


    }


    /**
    *从url中获取到Bitmap
    * @description:
    * @author ldm
    * @date 2015-8-11 下午1:55:12
    */
    public Bitmap getBitmapByUrl(String urlStr) {
    Bitmap bitmap = null;
    InputStream is = null;
    try {
    URL url = new URL(urlStr);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    is = new BufferedInputStream(con.getInputStream());
    bitmap = BitmapFactory.decodeStream(is);
    con.disconnect();
    return bitmap;
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    finally {
    try {
    is.close();
    }
    catch (IOException e) {
    e.printStackTrace();
    }
    }
    return null;
    }


    public void loadImgByAsyncTask(ImageView img, String url) {
    mImageView = img;
    // 从缓存中取出图片
    Bitmap bitmap = getLruCaches(url);
    if (bitmap == null) {// 假设能在中无图片,则就从网络下载
    mImageView.setImageResource(R.drawable.ic_launcher);//设置默认图片
    new ImageAsyncTask(url).execute(url);
    }
    else {// 缓存中有图片。则直接显示出来
    mImageView.setImageBitmap(bitmap);
    }
    }


    private class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
    private ImageView imageView;
    private String mUrl;


    public ImageAsyncTask(String mUrl) {
    this.mUrl = mUrl;
    }


    @Override
    protected Bitmap doInBackground(String... params) {
    Bitmap bitmap = getBitmapByUrl(params[0]);// 获取图片
    if (bitmap != null) {
    setLruCaches(params[0], bitmap);
    }
    return getBitmapByUrl(params[0]);
    }


    @Override
    protected void onPostExecute(Bitmap result) {
    ImageView img = (ImageView) listView.findViewWithTag(mUrl);
    if (img != null && result != null) {
    imageView.setImageBitmap(result);
    }
    mTask.remove(this);
    }
    }


    public void setImageView(int start, int end) {
    for (int i = start; i < end; i++) {
    String url = DataAdapter.URLS[i];
    Bitmap bitmap = getLruCaches(url);
    if (bitmap == null) {// 假设能在中无图片,则就从网络下载
    ImageAsyncTask task = new ImageAsyncTask(url);
    task.execute(url);
    mTask.add(task);
    }
    else {// 缓存中有图片,则直接显示出来
    ImageView img = (ImageView) listView.findViewWithTag(url);
    img.setImageBitmap(bitmap);
    }
    }
    }
    public void stopAllTask(){
    if(mTask.size()>0){
    for (ImageAsyncTask task : mTask) {
    task.cancel(false);
    }
    }
    }
    }

       相应ListView的数据适配器DataAdapter:

    public class DataAdapter extends BaseAdapter implements OnScrollListener {
    private Context mContext;
    private List<DataBean> list;
    private ImageLoader mImageLoader;
    private int mSart;
    private int mEnd;
    public static String[] URLS;
    private ListView listView;
    private boolean isFirst;//是否是第一次进入 
    public DataAdapter(Context mContext, List<DataBean> list, ListView listView) {
    this.listView = listView;
    this.mContext = mContext;
    this.list = list;
    mImageLoader = new ImageLoader(listView);
    URLS = new String[list.size()];
    for (int i = 0; i < list.size(); i++) {
    URLS[i] = list.get(i).getImgUrl();
    }
    isFirst=true;
    listView.setOnScrollListener(this);
    }

    @Override
    public int getCount() {
    // TODO Auto-generated method stub
    return list.size();
    }

    @Override
    public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return list.get(arg0);
    }

    @Override
    public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return arg0;
    }

    @Override
    public View getView(int arg0, View view, ViewGroup arg2) {
    ViewHolder holder = null;
    if (view == null) {
    holder = new ViewHolder();
    view = LayoutInflater.from(mContext).inflate(R.layout.item_layout, null);
    holder.iv = (ImageView) view.findViewById(R.id.item_iv);
    holder.titleTv = (TextView) view.findViewById(R.id.item_title);
    holder.contentTv = (TextView) view.findViewById(R.id.item_content);
    view.setTag(holder);
    }
    else {
    holder = (ViewHolder) view.getTag();
    }
    holder.titleTv.setText(list.get(arg0).getTitle());
    holder.contentTv.setText(list.get(arg0).getContent());
    holder.iv.setTag(list.get(arg0).getImgUrl());// 为ImageView设置tag
    // new ImageLoader().loaderImageThread(holder.iv, list.get(arg0).getImgUrl());//用线程载入图片
    mImageLoader.loadImgByAsyncTask(holder.iv, list.get(arg0).getImgUrl());
    return view;
    }

    /***
    * ListView在流动过程中调用 
    */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    mSart = firstVisibleItem;// 可见第一个item
    mEnd = firstVisibleItem + visibleItemCount;// 可见的最后一个item
    if(isFirst&&visibleItemCount>0){//第一次载入数据时数据处理
    mImageLoader.setImageView(mSart, mEnd);
    isFirst=false;
    }
    }

    /***
    * ListView在流动状态变化时调用 
    */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (scrollState == SCROLL_STATE_IDLE) {// 流动停止,此时载入可见项数据
    mImageLoader.setImageView(mSart, mEnd);
    }
    else {// 停止载入数据
    mImageLoader.stopAllTask();
    }
    }
    class ViewHolder {
    TextView titleTv;
    TextView contentTv;
    ImageView iv;
    }
    }

  • 相关阅读:
    asp.net 中theme一个意外问题
    常用的APT命令参数
    使用分布式编译incredbuild错误error C2858: commandline option 'program database name 解决方法
    使用分布式编译incredbuild错误error C2858: commandline option 'program database name 解决方法
    闻名遐迩的MySQL乱码问题(转)
    让你在职场上不可替代的12信条 30句职场箴言
    让你在职场上不可替代的12信条 30句职场箴言
    常用的APT命令参数
    [转]深入理解SET NAMES和mysql(i)_set_charset的区别
    [转]深入理解SET NAMES和mysql(i)_set_charset的区别
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7358122.html
Copyright © 2020-2023  润新知