LoadImage一个从网络访问图片,并存到缓存(内存,磁盘)直接可以用

LoadImage类:

package com.tarena.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;

import com.tarena.util.DiskLruCache.Editor;
import com.tarena.util.DiskLruCache.Snapshot;

import android.R.integer;
import android.R.string;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;

public class ImageLoader {  
    //下载完成任务执行完毕后发消息
    public static final int LOAD_FINISH =102;
    public static final int NEW_TASK =102;


    //线程池中线程的数量、
    //(这个数量应该与设备cpu的核数相同)
    public static int Thread_Count;
    //上下文
    public static Context context;
    //内存
    public static LruCache<String, Bitmap> lruCache;
    //双向队列,以后可以根据自己的需求选择对应的FIFO或者LIFO;
    public static LinkedBlockingDeque<Runnable> blockingDeque;
    //线程池
    public static ExecutorService service;
    //从任务队列中取下载人物的handler
    public static Handler pollHandler;
    //任务下载完毕后,用来刷新ListView条目显示下载图片内容
    public static Handler uiHandler;
    //养活PollHandler
    public static Thread pollThread;
    //标示的作用,用来确保ImageView只要进行一次赋值就可以。
    public static boolean isFirstTiem = true;
    //存储到sdcard当中
    public static DiskLruCache diskLruCache;

    public ImageLoader(){

    }
    /**
     * 初始化所有属性的值
     * @param context  上下文
     */
    public static void inIt(Context context){


        //初始化上下文
        ImageLoader.context = context;
        //初始化线程池中线程的数量
        Thread_Count = getNumberOfCores();
        //最大的缓存运行空间,内存缓存
        lruCache = new LruCache<String, Bitmap>((int) (Runtime.getRuntime().maxMemory()/8)){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getHeight()*value.getRowBytes();
            }
        };
        //初始化磁盘缓存
        try {
            //参数是:第一个是文件存储的路径,第二个是项目版本号,一个Key对应几个Value,存储空间是多少
            diskLruCache = DiskLruCache.open(directory(), appVersion(), 1, 1024*1024*20);
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        //初始化消息队列
        blockingDeque = new LinkedBlockingDeque<Runnable>();
        //初始化线程池
        service = Executors.newFixedThreadPool(Thread_Count);

        uiHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == LOAD_FINISH) {
                    ValueObject vObject = (ValueObject) msg.obj;

                    ImageView imageView = vObject.imageView;
                    String url = vObject.url;
                    Bitmap bitmap = vObject.bitmap;
                    if (imageView.getTag().toString().equals(url)) {
                        imageView.setImageBitmap(bitmap);
                    }

                }else{
                    super.handleMessage(msg);
                }
            }
        };


        pollThread = new Thread(){
            @Override
            public void run() {
                Looper.prepare();
                pollHandler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        // TODO Auto-generated method stub
                        if (msg.what == NEW_TASK) {
                            try {
                                Runnable runnable = blockingDeque.takeFirst();
                                service.execute(runnable);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }else{
                            super.handleMessage(msg);
                        }
                    }
                };
                Looper.loop();
            }
        };
        pollThread.start();
        isFirstTiem = false;
    }
    private static int appVersion() {

        try {
            //获取系统的项目的版本号
            PackageInfo info = context.getPackageManager()
                    .getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 0;
    }
    private static File directory() {
        String path = context.getExternalCacheDir().getPath();

        return new File(path,"ImageLoaddercache");
    }
    /**
     * 确定线程的数量
     * @return
     */
    public static int getNumberOfCores(){
        File file = new File("/sys/devices/system/cpu/");

        File[] files = file.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String filename) {
                if (filename.matches("cpu[0-9]")) {
                    return true;
                }else{
                    return false;
                }
            }
        });

        if (files.length>0) {
            return files.length;
        }else{
            return 1;
        }
    }
    /**
     * 
     * @param url
     * @param imageView
     */
    public static void loadImag(final String url,final ImageView imageView){
        if (isFirstTiem) {
            throw new RuntimeException("ImageLoad 未初始化");
        }
        //判断,url所指定的图像是否在缓存中有保存
        //将url转换为MD5格式的字符串
        Bitmap bitmap = lruCache.get(getMD5(url));
        imageView.setTag(getMD5(url));
        if (bitmap != null) {
            Log.i("TAG", "图像是从内存缓存中加载的");
            imageView.setImageBitmap(bitmap);
            return;
        }

        //判断磁盘缓存中url所指定的图像是否在缓存中有保存
        try {
            Snapshot snap =diskLruCache.get(getMD5(url));

            if (snap != null) {
                InputStream inputStream = snap.getInputStream(0);
                bitmap = BitmapFactory.decodeStream(inputStream);
                //将从磁盘缓存中获得的图片放到内存缓存当中,下次还是直接去内存缓存
                lruCache.put(getMD5(url), bitmap);

                imageView.setImageBitmap(bitmap);
                return;
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        //内存缓存,磁盘缓存,当中都没有找到图片,就需要去网络中去获取图片
        blockingDeque.add(new Runnable() {

            @Override
            public void run() {
                try {
                    URL path = new URL(url);
                    HttpURLConnection connection = (HttpURLConnection) path.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                    connection.setDoInput(true);
                    connection.connect();
                    InputStream inputStream = connection.getInputStream();
                    //要适当的压缩处理
                    Bitmap bitmap = compress(inputStream,imageView);
                    inputStream.close();
                    //将从网络获取并处理过后的图片,存到内存缓存,
                    lruCache.put(getMD5(url), bitmap);
                    //将从网络获取并处理过后的图片,存到磁盘缓存,
                    //构建一个Editor对象,
                    Editor editor = diskLruCache.edit(getMD5(url));
                    //获取输出流对象
                    OutputStream outputStream = editor.newOutputStream(0);
                    //设置图片的压缩格式
                    bitmap.compress(CompressFormat.JPEG, 100, outputStream);
                    //提交Editor进行存储
                    editor.commit();
                    //记录日志的方法
                    diskLruCache.flush();

                    /*
                     * 在给主线程发消息的时候,我要解决图片的重复加载问题,光传一个Bitmap是解决不了的
                     * 所以我要出一个ValueObject(imageview,图的Url,图);
                     */
                    ValueObject object = new ValueObject(imageView, getMD5(url), bitmap);
                    //发消息到主线程,更新UI
                    Message.obtain(uiHandler, LOAD_FINISH,object).sendToTarget();

                } catch (Exception e) {
                    e.printStackTrace();
                }


            }

        });
        Message.obtain(pollHandler,NEW_TASK).sendToTarget();
    }

    private static class ValueObject{
        ImageView imageView ;
        String url;
        Bitmap bitmap;
        public ValueObject(ImageView imageView, String url, Bitmap bitmap) {
            super();
            this.imageView = imageView;
            this.url = url;
            this.bitmap = bitmap;
        }

    }

    /**
     * 根据要显示的ImageView的大小对图像进行压缩
     * @param inputStream  
     * @param imageView
     * @return
     */
    private static Bitmap compress(InputStream inputStream, ImageView imageView) {
        Bitmap bitmap = null;
        try {
            //1)现货的图像源的尺寸大小
            //借助Options来获得图像的大小
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte [] buff = new byte[4096];
            int len = -1;
            while ((len=inputStream.read(buff))!=-1) {
                out.write(buff,0,len);
            }

            Options opts = new Options();
            //如果设置了这句话,decodeByteArray返回值为Null;
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length, 
                    opts);
            int width = opts.outWidth;//图像的宽度(像素值)
            int height = opts.outHeight;//图像的高度(像素值)

            //在取ImageView的宽,高的时候。有的时候返回的是0
            int targetWidth = imageView.getWidth();
            int targetHeight = imageView.getHeight();
            //所以要进行判断,解决这种的情况,有两种解决办法,
            //可以手动制定宽,高
            if (targetHeight == 0 || targetWidth == 0) {
                //以当前设备的高度和宽度来作为压缩的依据
                targetWidth = context.getResources().getDisplayMetrics().widthPixels;
                targetHeight = context.getResources().getDisplayMetrics().heightPixels;
            }

            //计算压缩比
            int sampleSize = 1;
            //判断我去图片的宽,高去除我装图片的容器得到的值,如果大于1.
            if (width*1.0 / targetWidth >1 || height*1.0/targetHeight>1) {
                //就得到压缩比,他俩谁打取谁,记得要向上取整在转;
                sampleSize = (int) Math.ceil(Math.max((width*1.0 / targetWidth), (height*1.0/targetHeight)));
            }
            //设置压缩比
            opts.inSampleSize = sampleSize;
            //设置返回值不为空
            opts.inJustDecodeBounds = false;
            //获得压缩后的图片
            bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length, opts);
            out.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    private static String getMD5(String url){
        String result= "";
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.update(url.getBytes());

            byte [] bs = digest.digest();

            StringBuilder sb = new StringBuilder();
            for (byte b :bs) {
                String str= Integer.toHexString(b & 0xff);
                if (str.length() == 1) {
                    sb.append("0");
                }
                sb.append(str);
            }
            result = sb.toString();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值