Android图片异步加载的实现

android应用经常会遇到多个图片的加载。

我在写图片加载的思路是:先看内存中有没有,若没有去本地看有没有,最后去网络上下载。

上代码,抛砖引玉。


import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.drawable.BitmapDrawable;

import android.graphics.drawable.Drawable;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.support.annotation.Nullable;

import android.util.Base64;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.lang.ref.SoftReference;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.HashMap;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

* 异步图片加载器

* 2018-04-06

* StoneFu

*/

public class AsyncImageLoader {

private static final StringTAG="AsyncImageLoader";

    private static final StringDIR=".www.cctv.com";

    private static final int MSG_MEMORY=0;

    private static final int MSG_SDCARD=1;

    private static final int MSG_NET=2;

    private HashMap>imageCache;

    private ExecutorServicemExecutorService;

    private static AsyncImageLoadersAsyncImageLoader;

    private  AsyncImageLoader() {

imageCache =new HashMap<>();

        int i=Runtime.getRuntime().availableProcessors()/2+1;

        JLog.e(TAG+",AsyncImageLoader-->i:"+i);

        mExecutorService = Executors.newFixedThreadPool(i);

    }

public static AsyncImageLoadergetInstance(){

if(sAsyncImageLoader==null){

sAsyncImageLoader=new AsyncImageLoader();

        }

return sAsyncImageLoader;

    }

private StringgetFileName(String url){

String encodedString = Base64.encodeToString(url.getBytes(), Base64.DEFAULT);

        String name=""+encodedString+".jpg";

        return name;

    }

private DrawableloadDrawableFromSDCard(String url){

String name=getFileName(url);

        try{

File file=getFile(name);

            FileInputStream fis =new FileInputStream(file);

            Bitmap bitmap  = BitmapFactory.decodeStream(fis);

            if(bitmap!=null){

Drawable drawable=new BitmapDrawable(bitmap);

                return drawable;

            }

}catch (IOException e){

e.printStackTrace();

        }

return null;

    }

public void loadDrawable(final String imageUrl, final ImageCallback imageCallback) {

final  Handler handler =new Handler() {

public void handleMessage(@Nullable Message message) {

JLog.e("---------------------->msg.what:"+message.what);

                    imageCallback.imageLoaded((Drawable) message.obj, imageUrl);

                }

};

        //memory

        if (imageCache.containsKey(imageUrl)) {

SoftReference softReference =imageCache.get(imageUrl);

            Drawable drawable = softReference.get();

            if (drawable !=null) {

Message message = handler.obtainMessage(MSG_MEMORY, drawable);

                handler.sendMessage(message);

            }

}

//sdcard

        Drawable drawable=loadDrawableFromSDCard(imageUrl);

        if(drawable!=null){

imageCache.put(imageUrl, new SoftReference<>(drawable));

            Message message = handler.obtainMessage(MSG_SDCARD, drawable);

            handler.sendMessage(message);

return ;

        }

//net

        mExecutorService.execute(new Runnable() {

@Override

            public void run() {

Drawable drawable =loadImageFromUrl(imageUrl);

                if(drawable!=null){

Bitmap bmp=((BitmapDrawable)drawable).getBitmap();

                    saveBitmapToSDCard(bmp,getFileName(imageUrl),Bitmap.CompressFormat.JPEG);

                }

imageCache.put(imageUrl, new SoftReference(drawable));

                Message message =handler.obtainMessage(MSG_NET, drawable);

                handler.sendMessage(message);

            }

});

    }

private static DrawableloadImageFromUrl(String strUrl) {

URL url;

        InputStream i =null;

        try {

url =new URL(strUrl);

            i = (InputStream) url.getContent();

        }catch (MalformedURLException e1) {

e1.printStackTrace();

        }catch (IOException e) {

e.printStackTrace();

        }

Drawable d = Drawable.createFromStream(i, "src");

        return d;

    }

private FilegetFile(String name){

File appDir=new File(Environment.getExternalStorageDirectory(),DIR);

        if(!appDir.exists())

appDir.mkdir();

        File file=new File(appDir,name);

        return file;

    }

private  boolean saveBitmapToSDCard(Bitmap bitmap, String name, Bitmap.CompressFormat format){

JLog.e(TAG+",saveBitmapToSDCard");

        boolean isRet=true;

        FileOutputStream out;

        File file=getFile(name);

        try{

out=new FileOutputStream(file);

            bitmap.compress(format,100,out);

            out.flush();

            out.close();

        }catch (IOException e){

e.printStackTrace();

            isRet=false;

        }

return  isRet;

    }

public interface ImageCallback {

void imageLoaded(Drawable imageDrawable, String imageUrl);

    }

}

2018年4月24日更新

这个文章(http://dev.bizo.com/2014/06/cached-thread-pool-considered-harmlful.html)说明了直接使用Executors.newCachedThreadPool()不是最佳的。主要有以下两个原因:

1,FixedTheadPool 和 SignalThreadPool:允许的请求列对长度为Integer.MAX_VALUE,可能会堆积大量的请求,导致OOM.

2.CachedThreadPool 和 ScheduledThreadPool:允许创建线程数据为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

基于上述原因,ExecutorService的实例化如下:

private static final int KEEP_ALIVE_TIME=30;

private static final TimeUnitKEEP_ALIVE_TIME_UNIT=TimeUnit.SECONDS;

private BlockingQueueblockingQueue=new LinkedBlockingDeque();

private void initExecutorService(){

int i=Runtime.getRuntime().availableProcessors();

//JLog.e(TAG+",AsyncImageLoader-->i:"+i);

//mExecutorService = Executors.newFixedThreadPool(i);

mExecutorService=new ThreadPoolExecutor(i, i *2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, blockingQueue, new ThreadFactory() {

@Override

    public ThreadnewThread(@NonNull Runnable r) {

return null;

    }

}, new RejectedExecutionHandler() {

@Override

    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

}

});

}

facebook的开源的图片加载库

https://www.fresco-cn.org/docs/index.html

你可能感兴趣的:(Android图片异步加载的实现)