做一个懒惰高效的Android程序员

此系列文章目前包括:

  • 第一篇:介绍了RoboGuice库,它是一个依赖注入框架,可是节省很多代码,在APP开发中更加高效省时;
  • 第二篇:研究了关于Genymotion,相对于Android本地模拟器来说,它是一个超快的模拟器,在APP开发的过程中可以进行快速测试,项目更加高效;
  • 第三篇:探索了关于JSON解析库(GSON和Jackson),使用这些JSON解析库可以使提高APP的性能,也可以减少冗余无用的代码,让项目更加高效;
  • 第四篇:讲解了关于卡片布局界面,然后研究了一个卡片布局的库,最后做了一个卡片布局列表的简单例子。

关于本文

在这篇文章中,我们会介绍几种图片相关的开源库,帮助我们在开发过程中异步加载图片,自动缓存和下载图片。

Android加载图片必需的条件

几乎所有Android的APP都需要远程加载图片,在加载图片的时候,我们需要注意以下事项:

  • 加载图片必须在后台执行(也就是异步加载),防止阻塞UI线程;
  • 图片应该要进行循环利用;
  • 图片在加载完成后可以立刻显示;
  • 图片需要缓存使用;
  • 远程图片加载失败(网络连接不可用、url不可用或者别的原因)后,要处理得当,防止重复加载,且要保证只有网络可用时才进行加载;
  • 需要高效内存管理。

简单来说,就是要写代码实现图片加载的各个步骤过程。幸好目前已经有了很多很好的开源库,可以让我们进行异步加载图片,我们只需要调用图片加载函数和加载成功和加载失败的接口即可。

异步加载图片

假设有这么一个场景,我们需要加载50张图片和50条信息,然后需要把这些图片和文字加载到Listview中,在所有图片没有加载完成之前,Listview不会有任何显示。

这里的图片异步加载进程主要是针对图片。所谓异步图片加载就是一个后台进程,它在图片加载 的时候不会阻塞主线程,让用户可以同时进行别的操作。图片在后台线程中加载完成时会立刻显示。

异步图片加载库

下面看看使用Picasso和Universal Image Loader的例子:

实例一: Universal Image loader

第一步:需要初始化ImageLoader设置

1
2
3
4
5
6
7
8
9
10
11
12
public class MyApplication extends Application{
  
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
          
         // Create global configuration and initialize ImageLoader with this configuration
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).build();
        ImageLoader.getInstance().init(config);
    }
}

第二步:在AndroidManifest.xml中的Application标记中声明自定义的Application类。

第三步:加载图片然后显示到ImageView中

1
ImageLoader.getInstance().displayImage(objVideo.getThumb(), holder.imgVideo);

现在,Universal Image Loader提供了一个函数去实现加载成功或失败后的处理接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ImageLoader.getInstance().displayImage(photoUrl, imgView,
    new ImageLoadingListener() {
 
        @Override
        public void onLoadingStarted(String arg0, View arg1) {
            // TODO Auto-generated method stub
            findViewById(R.id.EL3002).setVisibility(View.VISIBLE);
        }
 
        @Override
        public void onLoadingFailed(String arg0, View arg1,
                FailReason arg2) {
            // TODO Auto-generated method stub
            findViewById(R.id.EL3002).setVisibility(View.GONE);
        }
 
        @Override
        public void onLoadingComplete(String arg0, View arg1,
                Bitmap arg2) {
            // TODO Auto-generated method stub
            findViewById(R.id.EL3002).setVisibility(View.GONE);
        }
 
        @Override
        public void onLoadingCancelled(String arg0, View arg1) {
            // TODO Auto-generated method stub
            findViewById(R.id.EL3002).setVisibility(View.GONE);
        }
    });

实例二:Picasso

直接加载图片:

1
Picasso.with(context).load("http://postimg.org/image/wjidfl5pd/").into(imageView);

调整图片大小:

1
2
3
4
5
Picasso.with(context)
  .load(imageUrl)
  .resize(100, 100)
  .centerCrop()
  .into(imageView)

实例三:UrlImageViewHelper

helper2

这是一个通过url来设置ImageView的内容的一个库,可以处理下载,缓存和自定义等等。

UrlImageViewHelper可以自动下载和管理图片和ImageView,重复的图片url不会重复加载,内部通过一个弱引用HashTable来进行内存缓存,只要发现图片不再被使用,它就会自动进行垃圾回收。

图片可以直接加载:

1
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png");

在下载的过程中可以设置一个正在加载的图片占位符:

1
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png", R.drawable.loadingPlaceHolder);

可以设置图片缓存一分钟:

1
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png", null, 60000);

实例四:Volley

Volley这个库是由Android官方团队开发的,它在2011年谷歌I/O大会上公布,十个月前我也写了一篇关于Volley库的文章 – Android – Volley library example,读者可以看一下,如果没有用过,也可以试着用一下。

接下来我们看看使用Volley的例子:

第一步:在xml布局文件中使用NetworkImageView。

第二步:定义一个ImageCache类。

如题所述,这里需要自己定义一个ImageCache类来初始化ImageLoader对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class BitmapLruCache
extends LruCache
        implements ImageLoader.ImageCache {
  
    public BitmapLruCache() {
        this(getDefaultLruCacheSize());
    }
  
    public BitmapLruCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }
  
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }
  
    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }
  
    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
  
    public static int getDefaultLruCacheSize() {
        final int maxMemory =
                (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
  
        return cacheSize;
    }
}

第三步:新建一个ImageLoader对象然后加载图片。

1
2
ImageLoader.ImageCache imageCache = new BitmapLruCache();
ImageLoader imageLoader = new ImageLoader(Volley.newRequestQueue(context), imageCache);

第四步:加载图片,设置到ImageView中。

1
2
NetworkImageView imgAvatar = (NetworkImageView) findViewById(R.id.imgDemo);
imageView.setImageUrl(url, imageLoader);

选择哪个库好呢?

怎么决定使用哪个库呢?我们来讲讲怎么选择。

事实上选择哪个库需要依项目需求而定,下面看看这些库的一些自己的特点,对比一下你就知道该怎么选择了。

Picasso:

  • 使用Picasso只需要一行代码。
  • 不需要初始化ImageLoader,也不用自己写ImageLoader单例。
  • Picasso可以指定目标图片的大小,在内存吃紧的时候或者在需要考虑性能的时候非常实用,为了加载速度可以替换掉一些图片。
  • Picasso未提供图片缩略图的方法。
  • 有时需要检测图片加载时的状态,正在加载,加载结束,加载失败或者取消加载等。很意外的是它没有提供这样的一个检测状态的接口。“fetch()”不会回传数据,”get()”只是作为异步读数据,“load()”用于异步绘制图形。

Universal Image Loader(UIL):

  • 这是目前最受欢迎的图片加载库,事实上它基于 Fedor Vlasov’s project的,它是关于图片加载的第一个完整的解决方案,也是StackOverFlow上最受欢迎的方案。(链接
  • UIL库有良好的文档,也有很好的例子展示了所有特性。
  • UIL提供了一个很简单的方式去下载图片。
  • UIL使用builders来进行定制,几乎所有东西都可以配置。
  • UIL不能指定下载图片的大小,里面很多定义都需要依靠view的大小。不过可以通过在源码中传递一个Imagesize参数来实现,这一点没有Picasso灵活。

Volley:

  • 这是Android开发团队官方出的,但是目前还没有出文档。
  • 它不仅仅是一个图片加载库,也是一个网络异步加载库。
  • 开发者必须自己定义一个ImageCache类,然后用它和RequestQueue类来构造ImageLoader对象。

综上,你应该可以对这些库进行对比了,选择什么库也还是不容易,因为这还是要依项目的需求来定。如果你的项目很大,那么可以考虑使用Picasso或者Universal Image Loader。如果你的项目只是一个小项目,那么可以考虑用Volley库,因为Volley不仅是一个图片加载库,还能提供一个最基本的网络加载通用解决方案。

我个人比较推荐使用Picasso,如果你想自己实现更多的控制和自定义的话,那就用Universal Image Loader吧

 

posted @ 2014-08-22 10:56  Martin2  阅读(278)  评论(0编辑  收藏  举报