Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Glide-渐进式加载初尝试

$
0
0

前言

前面我们讲解了渐进式加载的基础,接下来我们就讲一下在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.java

public 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.java

public 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.java

private 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.java

public 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

热门文章

作者:yulyu 发表于2017/3/14 17:02:38 原文链接
阅读:109 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>