Android必学-异步加载(二阶段:实现LruCache缓存)

在第二阶段中用LruCache实现了网络下载的图片的缓存,避免了重复下载图片,耗费流量。


首先要修改ImageLoader,其中被注释掉的代码就是一阶段中的代码:

public class ImageLoader {  
//  private ImageView mImageView;
//  private String mUrl;

    //在定义了一个成员变量mLruCache后,就不能每次在适配器的getView方法中去new一个ImageLoader了,因为下载的图片要缓存到同一LruCache中,不然就没用作用
    //因此只是用简单的多线程去实现异步加载是不行的了,因为适配器中只有一个ImageLoader的实例,
    //每次传入新的mImageView和mUrl的引用有可能会覆盖掉原来的引用,就会使得handleMessage
    //在调用ImageLoader唯一实例的mImageView和mUrl这两个成员变量时也许会与msg.obj中的bitmap不对应
    //所以sendMessage的时候,需要将showImageByThread方法的参数直接和bitmap绑定在一起传入message中
    //因此mImageView和mUrl也没有作用了
    private LruCache<String, Bitmap> mLruCache;

    public ImageLoader() {
        int maxMemory=(int) Runtime.getRuntime().maxMemory();
        int cacheSize=maxMemory/5;
        mLruCache=new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //在每次存入缓存的时候调用
                return value.getByteCount();
            };
        };
    }

    public void addBitmapToCache(String url,Bitmap bitmap) {
        if(mLruCache.get(url)==null) {
            mLruCache.put(url, bitmap);
        }
    }

    public Bitmap getBitmapFromCache(String url) {
        return mLruCache.get(url);
    }


    //因为在getView中每次都new一个ImageLoader实例,因此都有一个新的 handler成员变量,
    //所以尽管handleMessage是在主线程中进行,且handleMessage中用了ImageLoader实例mImageView和mUrl
    //但是bitmap中的bitmap会与正确的mImageView和mUrl对应,不会因为多线程而发生错乱
    private Handler handler=new Handler() {

        @Override
         public void handleMessage(android.os.Message msg) {
//          if (mImageView.getTag().equals(mUrl)) {
//              mImageView.setImageBitmap((Bitmap) msg.obj);
//          }

            ViewHolder vh=(ViewHolder)msg.obj;
            Bitmap bm=vh.bm;
            ImageView iv=vh.iv;
            String url=vh.url;
            if(iv.getTag().equals(url)) {
                iv.setImageBitmap(bm);
            }
        }
    };

    /**
     * 使用多线程实现异步加载
     * @param iv
     * @param url
     */
    public void showImageByThread(final ImageView iv, final String url) {
//      mImageView = iv;
//      mUrl = url;
//
//      new Thread() {
//
//          @Override
//          public void run() {
//              Bitmap bitmap = getBitmapFromURL(url);
//              Message message = Message.obtain();
//              message.obj = bitmap;
//              handler.sendMessage(message);
//          }
//      }.start();

        Bitmap bitmap=getBitmapFromCache(url);
        if (bitmap == null) {
            new Thread() {

                @Override
                public void run() {
                    Bitmap bm = getBitmapFromURL(url);
                    Message message = Message.obtain();
                    ViewHolder vh=new ViewHolder();
                    vh.iv=iv;
                    vh.url=url;
                    vh.bm=bm;
                    message.obj = vh;
                    handler.sendMessage(message);
                }
            }.start();
        }
        else {
            iv.setImageBitmap(bitmap);
        }

    }
    private class ViewHolder {
        public ImageView iv;
        public String url;
        public Bitmap bm;
    }

    /**
     * 使用AsyncTask实现异步加载,showImageByAsyncTask自身是在主线程当中的
     * @param iv
     * @param url
     */
    public void showImageByAsyncTask(final ImageView iv,final String url) {
        Bitmap bitmap=getBitmapFromCache(url);
        if (bitmap == null) {
            new LoadingAsyncTask(iv, url).execute(url);
        }
        else {
            iv.setImageBitmap(bitmap);
        }
    }

    private class LoadingAsyncTask extends AsyncTask<String, Void, Bitmap> {
        private ImageView imageView;
        private String url;

        public LoadingAsyncTask(ImageView iv,String url) {
            imageView=iv;
            this.url=url;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            Bitmap bm=getBitmapFromURL(params[0]);
            if(bm!=null) {
                addBitmapToCache(params[0], bm);
            }
            return bm;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            if (imageView.getTag().equals(url)) {
                imageView.setImageBitmap(result);
            }
        }
    }

    public Bitmap getBitmapFromURL(String urlString) {
        Bitmap bm=null;
        InputStream is=null;
        try {
            URL url=new URL(urlString);
            HttpURLConnection connection=(HttpURLConnection) url.openConnection();
            is=new BufferedInputStream(connection.getInputStream());
            bm=BitmapFactory.decodeStream(is);
            connection.disconnect();//释放资源
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bm;
    }
}

然后是在NewsAdapter中添加成员变量mImageLoader并在构造方法中初始化mImageLoader=new ImageLoader();
再修改getView方法的部分代码

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder=null;
        if(convertView==null) {
            viewHolder=new ViewHolder();
            convertView=mInflater.inflate(R.layout.item_layout, null);
            viewHolder.icon=(ImageView) convertView.findViewById(R.id.id_icon);
            viewHolder.title=(TextView) convertView.findViewById(R.id.id_tv_title);
            viewHolder.content=(TextView) convertView.findViewById(R.id.id_tv_content);
            convertView.setTag(viewHolder);
        }
        else {
            viewHolder=(ViewHolder) convertView.getTag();
        }
        viewHolder.icon.setImageResource(R.drawable.ic_launcher);
        String url=mList.get(position).newsIconUrl;
        viewHolder.icon.setTag(url);

//      new ImageLoader().showImageByAsyncTask(viewHolder.icon, url);
//      new ImageLoader().showImageByThread(viewHolder.icon, url);

        mImageLoader.showImageByAsyncTask(viewHolder.icon,url);
//      mImageLoader.showImageByThread(viewHolder.icon, url);
        viewHolder.title.setText(mList.get(position).newsTitle);
        viewHolder.content.setText(mList.get(position).newsContent);
        return convertView;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值