Android:异步加载图片

我们知道Android为了不阻塞UI线程(main线程),不允许在非UI线程中进行UI操作以及网络请求等操作,为了不阻塞UI,我们往往就要进行异步加载.

我们以异步加载图片为例子,来学习一下异步加载
在这里插入图片描述

方法一:Thread+Handler+Message

在这里插入图片描述

1.我们新建线程,在线程中获取图片(Bitmap对象)

new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    //Android中非主线程无法在线程中更新ui,可通过Handler把数据传递到主线程
                    Bitmap bitmap = getBitmapFromUrl(url);
                    //新建Message对象作为载体
                    Message message = Message.obtain();
                    //将Bitmap对象与消息绑定
                    message.obj = bitmap;
                    //通过Handler发送消息
                    mHandler.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

2.新建Handler用来传递消息,重写handleMessage方法,从Message中取出图片,并设置给ImageView.

 private Handler mHandler = new Handler() {
       @Override
       public void handleMessage(@NonNull Message msg) {
           super.handleMessage(msg);
           if (mImageView.getTag().equals(mUrl))  //只有ImageView的tag为当前url时,才进行设置
               mImageView.setImageBitmap((Bitmap) msg.obj);
       }
   };

方法二:AsyncTask

1.新建一个loadIMageAsynTask类并继承AsynTask,重写doInBackgroud和onPostExecute方法


public class loadImageAsynTask extends AsyncTask<String, Void, Bitmap> {//Params,Progress,Result

        private ImageView mImageView;
        private String mUrl;

        public loadImageAsynTask(ImageView imageView, String url) {
            mImageView = imageView;
            mUrl = url;
        }

        //在doInBackground方法中获取Bitmap对象,并返回
        @Override
        protected Bitmap doInBackground(String... urls) {
            Bitmap bitmap = null;
            try {
                //从网络上获取图片
                bitmap = getBitmapFromUrl(urls[0]);
                if (bitmap != null) {
                    //将下载好的图片保存到LruCache中s
                    mLruCache.put(urls[0], bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        //在onPostExecute方法中将Bitmap对象设置给ImageView
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (mImageView.getTag().equals(mUrl))
                mImageView.setImageBitmap(bitmap);
        }
    }

与Thread+Handler对比,AsyncTask有两个好处:

  1. 方便实现异步通信,不需使用 “任务线程(如继承Thread类) + Handler”的复杂组合
  2. 节省资源,采用线程池的缓存线程 + 复用线程,避免了频繁创建 & 销毁线程所带来的系统资源开销

进阶:异步加载图片的优化

问题1:

由于我们的模拟器网速很快,当我们加载上下滑动图片时不会发生什么问题,但是当我们网速很慢时(我们可以在获取图片时Sleep一秒来模拟网速慢的情况),我们就会发现当item 1,item 2,item 3都加载后我们加载item 4时,并不会直接在item 4 上设置image 4,而是先设置的image 1,image 2, image 3,再设置的image 4.

解决办法:为ImageView设置Tag

1.为View对象设置属性时,以图片的urlkey,设置为图片Tag.

viewHolder.ivIcon.setTag(mList.get(i).getNewsIconUrl());

2.在获得图片(Bitmap)后,设置给ImageView时,先进行判断

if (mImageView.getTag().equals(mUrl))
    mImageView.setImageBitmap(bitmap);
问题2:

我们每次滑动时,都是从网络重新获取图片,这对于用户来说,很耗流量.

解决办法:使用LruCache

1.新建LruCache,并重写sizeof方法,返回每次缓存的图片大小

mLruCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //在每次存入缓存中调用,告诉我们的系统存入的对象有多大
                return value.getByteCount();
            }
        };

2.每次从网络上获取图片后,加入到缓存

       //从网络上获取图片
       bitmap = getBitmapFromUrl(urls[0]);
       if (bitmap != null) {
          //将下载好的图片保存到LruCache中s
          mLruCache.put(urls[0], bitmap);
       }

3.如果缓存中有就从缓存中取,缓存中没有再发送网络请求获取图片

       Bitmap bitmap = null;
       //从缓存中取出对应的图片,如果缓存中没有,我们就从网络中去下载
       bitmap = mLruCache.get(urlString);
       if (bitmap == null) {
           new loadImageAsynTask(imageView, urlString).execute(urlString);
       } else {
           imageView.setImageBitmap(bitmap);
       }

Android异步加载图片源码:https://github.com/wantao666/AndroidDemo/tree/master/SynTask

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selenium399

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值