zoukankan      html  css  js  c++  java
  • Android 的图片异步请求加三级缓存 ACE

    使用xUtils等框架是很方便,但今天要用代码实现bitmapUtils 的功能,很简单,

    1 AsyncTask请求一张图片 

    ####AsyncTask

    #####AsyncTask是线程池+handler的封装 第一个泛型: 传参的参数类型类型(和doInBackground一致) 第二个泛型:
    #####更新进度的参数类型(和onProgressUpdate一致) 第三个泛型: 返回结果的参数类型(和onPostExecute一致,
    #####和doInBackground返回类型一致)

    看AsyncTask源码:

    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
    
        private static final int CORE_POOL_SIZE = 5;
        private static final int MAXIMUM_POOL_SIZE = 128;
        private static final int KEEP_ALIVE = 1;
    
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };

    核心线程5 最大线程128  这是AsyncTask的线程池  然后通过handler发送消息 , 它内部实例化了一个静态的自定义类 InternalHandler,这个类是继承自 Handler 的,在这个自定义类中绑定了一个叫做 AsyncTaskResult 的对象,每次子线程需要通知主线程,就调用 sendToTarget 发送消息给 handler自己。然后在 handler 的 handleMessage 中 AsyncTaskResult 根据消息的类型不同(例如 MESSAGE_POST_PROGRESS 会更新进度条,MESSAGE_POST_CANCEL 取消任务)而做不同的操作,值得一提的是,这些操作都是在UI线程进行的,意味着,从子线程一旦需要和 UI 线程交互,内部自动调用了 handler 对象把消息放在了主线程了。

     private static final InternalHandler sHandler = new InternalHandler();

     mFuture = new FutureTask<Result>(mWorker) {
               @Override
                protected void More ...done() {
                    Message message;
                   Result result = null;
                    try {
                        result = get();
                   } catch (InterruptedException e) {
                        android.util.Log.w(LOG_TAG, e);
                   } catch (ExecutionException e) {
                        throw new RuntimeException("An error occured while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
                               new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
                        message.sendToTarget();
                        return;
                    } catch (Throwable t) {
                        throw new RuntimeException("An error occured while executing "
                               + "doInBackground()", t);
                    }
    
                    message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                            new AsyncTaskResult<Result>(AsyncTask.this, result));
                    message.sendToTarget();
               }
            };
      private static class InternalHandler extends Handler {
            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
            @Override
            public void More ...handleMessage(Message msg) {
                AsyncTaskResult result = (AsyncTaskResult) msg.obj;
                switch (msg.what) {
                    case MESSAGE_POST_RESULT:
                        // There is only one result
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                    case MESSAGE_POST_CANCEL:
                        result.mTask.onCancelled();
                        break;
                }
            }
        }

    下面看代码 第一步我们先请求一张图片 并解析 注释写的很详细了.

    NetCacheUtils.java

    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.widget.ImageView;
    
    /**
     * 网络缓存
     * 
     * @author Ace
     * @date 2016-02-18
     */
    public class NetCacheUtils {
    
        private LocalCacheUtils mLocalUtils;
        private MemoryCacheUtils mMemoryUtils;
    
        public NetCacheUtils(LocalCacheUtils localUtils,
                MemoryCacheUtils memoryUtils) {
            mLocalUtils = localUtils;
            mMemoryUtils = memoryUtils;
        }
    
        public void getBitmapFromNet(ImageView imageView, String url) {
            BitmapTask task = new BitmapTask();
            task.execute(imageView, url);
        }
    
        /**
         * AsyncTask是线程池+handler的封装 第一个泛型: 传参的参数类型类型(和doInBackground一致) 第二个泛型:
         * 更新进度的参数类型(和onProgressUpdate一致) 第三个泛型: 返回结果的参数类型(和onPostExecute一致,
         * 和doInBackground返回类型一致)
         */
        class BitmapTask extends AsyncTask<Object, Integer, Bitmap> {
    
            private ImageView mImageView;
            private String url;
    
            // 主线程运行, 预加载
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
    
            // 子线程运行, 异步加载逻辑在此方法中处理
            @Override
            protected Bitmap doInBackground(Object... params) {
                mImageView = (ImageView) params[0];
                url = (String) params[1];
                mImageView.setTag(url);// 将imageView和url绑定在一起
                // publishProgress(values)//通知进度
    
                // 下载图片
                return download(url);
            }
    
            // 主线程运行, 更新进度
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
            }
    
            // 主线程运行, 更新主界面
            @Override
            protected void onPostExecute(Bitmap result) {
                if (result != null) {
                    // 判断当前图片是否就是imageView要的图片, 防止listview重用导致的图片错乱的情况出现
                    String bindUrl = (String) mImageView.getTag();
                    if (bindUrl.equals(url)) {
                        // 给imageView设置图片
                        mImageView.setImageBitmap(result);
      // 将图片保存在本地
                        mLocalUtils.setBitmapToLocal(result, url);
    
                        // 将图片保存在内存
                        mMemoryUtils.setBitmapToMemory(url, result);
                    }
                }
            }
    
        }
    
        /**
         * 下载图片
         * 
         * @param url
         */
        public Bitmap download(String url) {
            HttpURLConnection conn = null;
            try {
                conn = (HttpURLConnection) (new URL(url).openConnection());
    
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                conn.setRequestMethod("GET");
    
                conn.connect();
    
                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    InputStream in = conn.getInputStream();
                    // 将流转化为bitmap对象
                    Bitmap bitmap = BitmapFactory.decodeStream(in);
                    return bitmap;
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
    
            return null;
        }
    
    }
    MemoryCacheUtils.java  用到了LruCache 很简单
    我简单翻译下文档:

    * A cache that holds strong references to a limited number of values. Each time 
    
    * a value is accessed, it is moved to the head of a queue. When a value is 
    
    * added to a full cache, the value at the end of that queue is evicted and may  
    * become eligible for garbage collection. 
    
    * Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
    * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。

    * <p>If your cached values hold resources that need to be explicitly released,
    * override {@link #entryRemoved}.
    * 如果你cache的某个值需要明确释放,重写entryRemoved()

    * <p>By default, the cache size is measured in the number of entries. Override
    * {@link #sizeOf} to size the cache in different units. For example, this cache
    * is limited to 4MiB of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的
    * 大小。

    1.  {@code 
    2.  *   int cacheSize = 4 * 1024 * 1024; // 4MiB 
    3.  *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { 
    4.  *       protected int sizeOf(String key, Bitmap value) { 
    5.  *           return value.getByteCount(); 
    6.  *       } 
    7.  *   }}

    -------------------------------------------------------------------

    <p>This class is thread-safe. Perform multiple cache operations atomically by
    * synchronizing on the cache: <pre> {@code
    * synchronized (cache) {
    * if (cache.get(key) == null) {
    * cache.put(key, value);
    * }
    * }}</pre>
    * 他是线程安全的,自动地执行多个缓存操作并且加锁

    -------------------------

    <p>This class does not allow null to be used as a key or value. A return
    * value of null from {@link #get}, {@link #put} or {@link #remove} is
    * unambiguous: the key was not in the cache.
    * 不允许key或者value为null
    * 当get(),put(),remove()返回值为null时,key相应的项不在cache中

    最重要的大概就是以上几点: 使用很简单
    来看代码
    import android.graphics.Bitmap;
    import android.support.v4.util.LruCache;
    
    /**
     * 内存缓存工具类
     * 
     * @author Ace
     * @date 2016-02-19
     */
    public class MemoryCacheUtils {
    
    
        // Android 2.3 (API Level
        // 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠,建议用LruCache,它是强引用
    
        private LruCache<String, Bitmap> mCache;
    
        public MemoryCacheUtils() {
            int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取虚拟机分配的最大内存
                                                                    // 16M
            // LRU 最近最少使用, 通过控制内存不要超过最大值(由开发者指定), 来解决内存溢出,就像上面翻译的所说 如果cache满了会清理最近最少使用的缓存对象
            mCache = new LruCache<String, Bitmap>(maxMemory / 8) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    // 计算一个bitmap的大小
                    int size = value.getRowBytes() * value.getHeight();// 每一行的字节数乘以高度
                    return size;
                }
            };
        }
    
        public Bitmap getBitmapFromMemory(String url) {
    
            return mCache.get(url);
        }
    
        public void setBitmapToMemory(String url, Bitmap bitmap) {
    
            mCache.put(url, bitmap);
        }
    
    }
    
    

    最后一级缓存 本地缓存 把网络下载的图片 文件名以MD5的形式保存到内存卡的制定目录

    /**
     * 本地缓存工具类
     * 
     * @author Ace
     * @date 2016-02-19
     */
    public class LocalCacheUtils {
    
        // 图片缓存的文件夹
        public static final String DIR_PATH = Environment
                .getExternalStorageDirectory().getAbsolutePath()
                + "/ace_bitmap_cache";
    
        public Bitmap getBitmapFromLocal(String url) {
            try {
                File file = new File(DIR_PATH, MD5Encoder.encode(url));
    
                if (file.exists()) {
                    Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
                            file));
                    return bitmap;
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        public void setBitmapToLocal(Bitmap bitmap, String url) {
            File dirFile = new File(DIR_PATH);
    
            // 创建文件夹 文件夹不存在或者它不是文件夹 则创建一个文件夹.mkdirs,mkdir的区别在于假如文件夹有好几层路径的话,前者会创建缺失的父目录 后者不会创建这些父目录
            if (!dirFile.exists() || !dirFile.isDirectory()) {
                dirFile.mkdirs();
            }
    
            try {
                File file = new File(DIR_PATH, MD5Encoder.encode(url));
                // 将图片压缩保存在本地,参1:压缩格式;参2:压缩质量(0-100);参3:输出流
                bitmap.compress(CompressFormat.JPEG, 100,
                        new FileOutputStream(file));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    MD5Encoder 

    import java.security.MessageDigest;
    
    public class MD5Encoder {
        
        public static String encode(String string) throws Exception {
            byte[] hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
            StringBuilder hex = new StringBuilder(hash.length * 2);
            for (byte b : hash) {
                if ((b & 0xFF) < 0x10) {
                    hex.append("0");
                }
                hex.append(Integer.toHexString(b & 0xFF));
            }
            return hex.toString();
        }
    }

    最后新建一个工具类来使用我们上面的三个缓存工具类

    /**
     * 三级缓存工具类
     * 
     * @author Ace
     * @date 2016-02-19
     */
    public class MyBitmapUtils {
    
        // 网络缓存工具类
        private NetCacheUtils mNetUtils;
        // 本地缓存工具类
        private LocalCacheUtils mLocalUtils;
        // 内存缓存工具类
        private MemoryCacheUtils mMemoryUtils;
    
        public MyBitmapUtils() {
            mMemoryUtils = new MemoryCacheUtils();
            mLocalUtils = new LocalCacheUtils();
            mNetUtils = new NetCacheUtils(mLocalUtils, mMemoryUtils);
        }
    
        public void display(ImageView imageView, String url) {
            // 设置默认加载图片
            imageView.setImageResource(R.drawable.news_pic_default);
    
            // 先从内存缓存加载
            Bitmap bitmap = mMemoryUtils.getBitmapFromMemory(url);
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap);
                System.out.println("从内存读取图片啦...");
                return;
            }
    
            // 再从本地缓存加载
            bitmap = mLocalUtils.getBitmapFromLocal(url);
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap);
                System.out.println("从本地读取图片啦...");
                // 给内存设置图片
                mMemoryUtils.setBitmapToMemory(url, bitmap);
                return;
            }
    
            // 从网络缓存加载
            mNetUtils.getBitmapFromNet(imageView, url);
        }
    
    }
     
  • 相关阅读:
    C#小数点位数处理方法
    C#获取硬盘空间信息
    Linux双网卡绑定实现负载均衡
    CentOS、Ubuntu配置网卡子接口
    CentOS7修改网卡名称,禁用ipv6
    centos命令自动补全增强
    使用批处理文件访问ORACLE数据库
    Mac 常用终端命令
    常用正则表达式
    pickle 模块
  • 原文地址:https://www.cnblogs.com/AceIsSunshineRain/p/5199650.html
Copyright © 2011-2022 走看看