在我们日常的开发过程中,我们免不了要跟图片打交道,尤其是网络图片,在我们处理这些问题的时候,较为常见的会遇到这样几个问题:一是OOM内存溢出,二是图片尺寸与缩略图处理的平衡,三是网络图片的加载与缓存机制,我们自己去处理这些问题的时候往往是比较麻烦的,常见的解决方案就是使用封装好的图片框架进行处理,我这里是根据在极客学院中学习的视频教程做了一个笔记,将它记录下来,为了以后方便回顾与总结。这里用到了两款比较优秀的图片处理库,分别是:Universal-ImageLoader和Picasso。

首先来看一下Universal-ImageLoader,这是目前android主流的图片处理框架之一,它为我们解决了很多日常开发中较为难处理的问题,比如:加载大图片时导致的OOM,网络图片的加载与缓存,多线程以及图片压缩处理等问题,它对外提供了比较完善的API,我们只需要根据自己的需求进行调用即可。

下面再来看一下Picasso,这是美国Square公司开源的一个android图形缓存库,可以加载本地或网络图片并自动缓存处理。从总体上来看,这两款框架都有高效的下载和缓存性能,只不过Universal-ImageLoader的功能多,而Picasso则使用复杂的图片压缩转换来尽可能的减少内存消耗。

具体使用:这里简单的说几种常用的:首先来看Universal-ImageLoader的使用方法:首先我们可以创建一个类去继承我们的Application,然后全局的给给ImageLoader设置一些配置参数,代码如下:

 

package com.jarchie.imageprocessdemo;

import android.app.Application;
import android.graphics.Bitmap;
import android.os.Environment;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import java.io.File;

/**
 * Created by Jarchie on 17/1/10.
 * 创建ImageLoader的配置信息
 */

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
                //max width,max height即保存每个缓存文件的最大长宽
                .memoryCacheExtraOptions(480,800)
                //设置硬盘缓存
                .diskCacheExtraOptions(480,800,null)
                //线程池内加载的数量
                .threadPoolSize(3)
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .denyCacheImageMultipleSizesInMemory()
                .memoryCache(new UsingFreqLimitedMemoryCache(2*1024*1024))
                //设置内存缓存的大小
                .memoryCacheSize(2 * 1024 * 1024)
                //硬盘设置的最大缓存数
                .diskCacheSize(50 * 1024 * 1024)
                //将手机sd卡里面的缓存文件名称用MD5加密
                .diskCacheFileNameGenerator(new Md5FileNameGenerator())
                .tasksProcessingOrder(QueueProcessingType.LIFO)
                //缓存文件的数量
                .diskCacheFileCount(100)
                //缓存文件的路径
                .diskCache(new UnlimitedDiscCache(new File(
                        Environment.getExternalStorageDirectory()
                        + "myApp/imageCache")))
                //加载图片默认的配置信息
                .defaultDisplayImageOptions(getDisplayOptions())
                //图片加载时的配置,连接时间和加载超时的时间
                .imageDownloader(new BaseImageDownloader(this,5*1000,30*1000))
                //写入加载时的错误日志
                .writeDebugLogs()
                //构建完成
                .build();
        ImageLoader.getInstance().init(configuration);
    }

    private DisplayImageOptions getDisplayOptions(){
        DisplayImageOptions options;
        options = new DisplayImageOptions.Builder()
                //设置图片在下载期间显示的图片
                .showImageOnLoading(R.mipmap.ic_launcher)
                //设置Uri为空或是错误的时候显示的图片
                .showImageForEmptyUri(R.mipmap.ic_launcher)
                //设置图片加载/解码过程中错误时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher)
                //设置下载的图片是否缓存在内存中
                .cacheInMemory(true)
                //设置下载的图片是否缓存在sd卡中
                .cacheOnDisk(true)
                //是否考虑JPEG图像EXIF参数(旋转,翻转)
                .considerExifParams(true)
                //设置图片以如何的编码方式显示
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
                //设置图片的解码类型
                .bitmapConfig(Bitmap.Config.RGB_565)
                //设置下载前的延迟时间
                //.delayBeforeLoading(int delayMills)
                //图片加入缓存前,对bitmap进行设置
                //.postProcessor(BitmapProcessor processor)
                //设置图片在下载前是否重置,复位
                .resetViewBeforeLoading(true)
                //是否设置为圆角,弧度是多少
                .displayer(new RoundedBitmapDisplayer(20))
                //设置图片加载好后渐入的动画时间
                .displayer(new FadeInBitmapDisplayer(100))
                //构建完成
                .build();
        return options;
    }

}

 

由于要访问网络和本地图片,所以我们需要在清单文件中加上对应的权限,还要指定Application为我们自己的App这个类,然后在我们的Activity中首先去实例化我们的ImageLoader,loader = ImageLoader.getInstance();

 

 

接下来我们分几种情况去说明,当我们加载本地图片的时候:调用displayImage()这个方法,传入两个参数,首先指定我们的图片路径,图片地址和图片控件,具体实现为:

 

//加载本地图片
String uri = "file:///" + Environment.getExternalStorageDirectory()
        + File.separator+"1483690114524.jpg";
loader.displayImage(uri,imageView);

当我们加载网络图片的时候,我们同样的调用displayImage()方法,然后传入两个参数,一个是网络地址,一个是图片控件,具体实现为:

 

 

//加载网络图片
loader.displayImage(imageUrl,imageView);

当我们加载带有监听的网络图片时,同样的调用displayImage()方法,传入三个参数,分别为图片地址,图片控件和监听的回调,这时会重写几个方法,我们可以根据自己的需求,在对应的回调方法里面去做具体的操作,具体代码为:

 

 

//加载带有监听事件的网络图片
loader.displayImage(imageUrl, imageView, new ImageLoadingListener() {
    @Override
    public void onLoadingStarted(String s, View view) {
        Log.e(TAG, "onLoadingStarted");
    }

    @Override
    public void onLoadingFailed(String s, View view, FailReason failReason) {
        Log.e(TAG, "onLoadingFailed");
    }

    @Override
    public void onLoadingComplete(String s, View view, Bitmap bitmap) {
        Log.e(TAG, "onLoadingComplete");
    }

    @Override
    public void onLoadingCancelled(String s, View view) {
        Log.e(TAG, "onLoadingCancelled");
    }
});

再来看一下Picasso的具体使用,由于相对应的API有很多,我们这里也简单的抽取3个方法来加以说明,首先普通的加载图片如何使用呢?由于Picasso在使用时是链式调用的,所以这里我们首先调用with()方法,传入上下文对象,接着调用load()方法传入图片地址(本地路径和网络路径都可以,根据需求指定即可),最后再调用into()方法,传入要显示的控件即可,具体实现代码为:

 

 

Picasso.with(MainActivity.this)
        .load(imageUrl)
        .into(imageView);

当我们需要二次对图片大小进行指定时,我们可以再调用一个resize()方法,传入指定的宽和高即可,具体代码为:

 

 

Picasso.with(MainActivity.this)
        .load(imageUrl)
        .resize(200,240).into(imageView);

当我们需要在加载图片失败的时候设置上一张我们自己的图片时,我们可以调用一个error()方法,传入一个指定的图片即可,具体实现为:

 

 

Picasso.with(MainActivity.this)
        .load(imageUrl)
        .error(R.mipmap.ic_launcher).into(imageView);

附源码:

 

activity_main.xml

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jarchie.imageprocessdemo.MainActivity">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</RelativeLayout>

MainActivity.java

 

 

package com.jarchie.imageprocessdemo;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.squareup.picasso.Picasso;
import java.io.File;

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private ImageLoader loader;
    private ImageView imageView;
    private String imageUrl = "http://www.kekegold.com/d/file/yule/star/2016-12-03/6968613360f003da4a228648f737a0fa.jpg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
//        imageloaderDisImg();
        picassoDisImg();
    }

    //采用Picasso加载图片
    private void picassoDisImg(){
//        Picasso.with(MainActivity.this)
//                .load(imageUrl)
//                .into(imageView);
//        Picasso.with(MainActivity.this)
//                .load(imageUrl)
//                .resize(200,240).into(imageView);
        Picasso.with(MainActivity.this)
                .load(imageUrl)
                .error(R.mipmap.ic_launcher).into(imageView);
    }

    //采用Universal-ImageLoader加载图片
    private void imageloaderDisImg(){
        //实例化我们的ImageLoader
        loader = ImageLoader.getInstance();
        //加载本地图片
//        String uri = "file:///" + Environment.getExternalStorageDirectory()
//                + File.separator+"1483690114524.jpg";
//        loader.displayImage(uri,imageView);
        //加载网络图片
//        loader.displayImage(imageUrl,imageView);
        //加载带有监听事件的网络图片
        loader.displayImage(imageUrl, imageView, new ImageLoadingListener() {
            @Override
            public void onLoadingStarted(String s, View view) {
                Log.e(TAG, "onLoadingStarted");
            }

            @Override
            public void onLoadingFailed(String s, View view, FailReason failReason) {
                Log.e(TAG, "onLoadingFailed");
            }

            @Override
            public void onLoadingComplete(String s, View view, Bitmap bitmap) {
                Log.e(TAG, "onLoadingComplete");
            }

            @Override
            public void onLoadingCancelled(String s, View view) {
                Log.e(TAG, "onLoadingCancelled");
            }
        });
    }

}