Glide-渐进式加载初尝试

Posted 夏雨_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glide-渐进式加载初尝试相关的知识,希望对你有一定的参考价值。

前言

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

热门文章

以上是关于Glide-渐进式加载初尝试的主要内容,如果未能解决你的问题,请参考以下文章

Glide-源码详解

Glide-源码详解

Android中图片加载框架Glide解析2----从源码的角度理解Glide的执行流程

PWA初体验

Glide的基本用法

Android图片加载框架最全解析,从源码的角度理解Glide的执行流程