Glide-渐进式加载初尝试

来源:互联网 发布:2009年网络歌曲排行榜 编辑:程序博客网 时间:2024/05/21 09:01

前言

前面我们讲解了渐进式加载的基础,接下来我们就讲一下在app中具体如何实现渐进式加载

1.基础

关于渐进式加载的基础知识,我们已经在前面讲解过了,这里就不重复讲解了,但是不代表不重要.

渐进式加载-基础讲解

http://blog.csdn.net/yulyu/article/details/61915471

2.背景

Android图片加载主要有四大框架,但是只有Fresco框架是可以支持渐进式加载(需要设置)

笔者是由于项目已经使用Glide,且跟换框架成本太大,所以才尝试用Glide实现渐进式加载,但是Glide本身框架目前是不适合做渐进式加载,里面的请求是将整个InputStream转化为bitmap后才通过回调设置给ImageView,这个过程只能走一次.笔者做了很多尝试来让Glide实现渐进式加载,虽然最后实现了这个功能,但是会破坏Glide的结构,影响内部的一些优化和设置,比如缓存和防止错位等,所以这里就不介绍这个实现过程了,但是在这个过程中,使用到一些实现渐进式加载的操作,可以介绍一下.

3.实现

首先我们定义一个类,来通过网络请求来获取InputStream
(HttpUrlFetcher是glide里面的一个实现类,这里将里面的代码简化一下,拿来使用)

//HttpUrlFetcher.javapublic class HttpUrlFetcher {    private static final String TAG = "HttpUrlFetcher";    private HttpURLConnection urlConnection;    private int               size;    public int getSize() {        return size;    }    public InputStream loadData(URL url)            throws IOException {        urlConnection = (HttpURLConnection) url.openConnection();        urlConnection.setConnectTimeout(2500);        urlConnection.setReadTimeout(2500);        urlConnection.setUseCaches(false);        urlConnection.setDoInput(true);        size = urlConnection.getContentLength();        final int statusCode = urlConnection.getResponseCode();        if (statusCode / 100 == 2) {            return urlConnection.getInputStream();        }        return null;    }}

找到控件和设置图片链接(此链接的图片是支持渐进式加载的JPEG图片)

//MainActivity    url = "http://www.reasoft.com/tutorials/web/img/progress.jpg";    iv1 = (ImageView) findViewById(R.id.iv1);

在子线程中请求网络并实现渐进式加载

//MainActivity.javapublic void show(View v) {    isCancel = false;    new Thread(new Runnable() {        @Override        public void run() {            try {                //网络请求                InputStream inputStream = httpUrl.loadData(new URL(url));                //创建一个和总数据一样大的数组来当容器                byte[]      bytes       = new byte[httpUrl.getSize()];                byte        lastOne     = 0;                byte        lastTwo     = 0;                int         offest      = 0;                while (!isCancel) {                    //本次读取的字节                    byte[] get = getBytes(inputStream);                    //放入本次读取的数据                    System.arraycopy(get, 0, bytes, offest, get.length);                    offest = offest + get.length;                    //记录最后两位字符                    lastOne = bytes[offest - 1];                    lastTwo = bytes[offest - 2];                    //替换掉最后两个字节为FFD9,否则无法转化成bitmap                    bytes[offest - 2] = -1;                    bytes[offest - 1] = -39;                    //生成bitmap                    Bitmap result = BitmapFactory.decodeByteArray(bytes, 0, offest);                    //还原最后两个字节                    bytes[offest - 2] = lastTwo;                    bytes[offest - 1] = lastOne;                    Message obtain = Message.obtain();                    Bundle  bundle = new Bundle();                    bundle.putParcelable(BITMAP, result);                    obtain.setData(bundle);                    handler.sendMessage(obtain);                }            } catch (IOException e) {                e.printStackTrace();            }        }    }).start();}

//MainActivity.javaprivate Handler handler = new Handler() {    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        Bitmap bitmap = msg.getData().getParcelable(BITMAP);        if (bitmap != null) {            iv1.setImageBitmap(bitmap);        }    }};

//MainActivity.javapublic static byte[] getBytes(InputStream is) throws IOException {    ByteArrayOutputStream outstream = new ByteArrayOutputStream();    //这里设置每次读取的数量,设置小一点是为了让效果更明显    byte[] buffer = new byte[10]; // 用数据装    int    len    = -1;    //要实现比较理想的渐进式加载效果,其实不应该写死每次读取量,应该是根据FFDA来判断读到第几帧了,然后决定是否需要显示了    if ((len = is.read(buffer)) != -1) {        outstream.write(buffer, 0, len);    } else {        is.close();    }    outstream.close();    // 关闭流一定要记得。    return outstream.toByteArray();}

这里有几个地方要注意的 :

  • 1.BitmapFactory.decodeByteArray方法读取的字节数组,jpg文件开头得是FFD8,结尾得是FFD9,不然的话会返回null,所以这边在每次解析的时候都将最后两位临时换成FFD9
  • 2.这里 FF D9是十六进制的,需要转换为二进制,并且取补码,最后的字节是 -1,-39
  • 3.记得增加网络权限

4.其他

本节代码很多地方写得不严禁,效率也不高,目的主要是介绍如何实现渐进式加载.但是笔者认为java在处理这类情况时,其实本身效率并不高,在实际项目使用中,如果对性能要求比较高的话,这类操作还是用C语言等底层来写,Android只是通过JNI来调用,这样更加合理和高效.

5.0 Demo源码

Demo

https://github.com/yulyu2008/ProgressiveDemo

热门文章

  • Glide-源码详解
  • 渐进式加载-基础讲解
  • 活用productFlavors
  • onTouch事件传递
  • 那些年我们解决滑动冲突时遇过的坑
  • 进程间通信–AIDL
  • 序列化–Serializable与Parcelable
  • 如何解决内存溢出以及内存泄漏
  • Okhttputils终极封装
  • FaceBook推出的调试神器
  • Android代码优化工具
  • Glide-入门教程
  • Glide-图片预处理(圆角,高斯模糊等)
  • Glide-图片的压缩
  • Glide-内存缓存与磁盘缓存
  • Glide-自定义缓存
1 0