安卓网络请求图片到图片的三级缓存技术(内存缓存,本地缓存,网络缓存)

安卓网络请求图片,对于我们来说并不陌生,因为每个应用都有可能会用到这一技术。通常情况下,我们第一次都是从网络上请求图片资源,然后将

图片资源保存到内存和本地,下一次动态显示图片的时候就不需要再从网络上请求图片资源了,直接从本地或者内存中获取就可以了。这就涉及到图片

的三级缓存技术,分别是内存缓存,本地缓存,网络缓存。

缓存的流程图:

首先我们定义一个类叫ClassLoader:

package com.jsako.showprodinfodemo;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

/**
 * 图片加载类
 *
 * @author Administrator
 *
 */
public class ImageLoader {
    private Context context;
    private int loadingImage;
    private int errorImage;
    private LruCache<String, Bitmap> mapCache;
    public ImageLoader(Context context, int loadingImage, int errorImage) {
        this.context = context;
        this.loadingImage = loadingImage;
        this.errorImage = errorImage;
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int mCacheSize = maxMemory / 8;
        mapCache = new LruCache<String, Bitmap>(mCacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    public void getAndSetImage(String imagePath, ImageView iv_image) {
        //保存当前的ImageView对应的imagepath
        iv_image.setTag(imagePath);
        iv_image.setImageResource(loadingImage);
        /*
         * 从第一级缓存中找对应imagePath的图片 如果第一级缓存有对应图片,显示! 如果第一级缓存没有图片,从第二级缓存中找
         */
        Bitmap bitmap = getImageByFirstCache(imagePath);
        if (bitmap != null) {
            iv_image.setImageBitmap(bitmap);
            System.out.println("从一级缓存中找到");
            return;
        }
        /*
         * 从第二级缓存中找对应的图片 如果有,则缓存到第一缓存中 如果没有,则从第三集缓存中找
         */
        bitmap = getImageBySecondCache(imagePath);
        if (bitmap != null) {
            iv_image.setImageBitmap(bitmap);
            cacheInFirst(imagePath, bitmap);
            System.out.println("从二级缓存中找到");
            return;
        }

        /*
         * 从第三级缓存中找对应的图片 如果有,则缓存到第一、二缓存中 如果没有,则显示错误的图片
         */
        loadImageByThridCache(imagePath, iv_image);
    }

    /**
     * 将图片缓存到一级缓存
     *
     * @param imagePath
     *            图片的url
     * @param bitmap
     */
    private void cacheInFirst(String imagePath, Bitmap bitmap) {

        mapCache.put(imagePath, bitmap);
    }

    /**
     * 从三级缓存中寻找图片
     *
     * @param imagePath
     *            图片的url
     * @param
     * @return
     */
    private void loadImageByThridCache(final String imagePath,
            final ImageView iv_image) {
        new AsyncTask<String, Void, Bitmap>() {
            /**
             * 开启异步任务前调用
             */
            @Override
            protected void onPreExecute() {

            }

            /**
             * 异步任务完成后调用
             */
            @Override
            protected void onPostExecute(Bitmap result) {
                String nowImagePath=(String) iv_image.getTag();
                if(!nowImagePath.equals(imagePath)){
                    //如果当前请求的图片路径和需要显示的图片路径不一致的话,就不显示图片
                    System.out.println("不显示图片了");
                    return;
                }

                if (result != null) {
                    iv_image.setImageBitmap(result);
                } else {
                    iv_image.setImageResource(errorImage);
                }
            }

            /**
             * 后台进行异步任务
             */
            @Override
            protected Bitmap doInBackground(String... params) {
                String nowImagePath=(String) iv_image.getTag();
                if(!nowImagePath.equals(params[0])){
                    //如果当前请求的图片路径和需要显示的图片路径不一致的话,就不进行网络请求了
                    System.out.println("不进行网络请求了");
                    return null;
                }
                String url = params[0];
                HttpURLConnection conn = null;
                try {
                    URL mUrl = new URL(url);
                    conn = (HttpURLConnection) mUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setReadTimeout(6000);
                    conn.setConnectTimeout(6000);
                    conn.setDoInput(true);
                    conn.connect();

                    int code = conn.getResponseCode();
                    if (code == 200) {
                        InputStream in = conn.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(in);
                        // 在分线程中缓存图片到一级和二级缓存
                        cacheInFirst(url, bitmap);
                        String imageName = url
                                .substring(url.lastIndexOf("/") + 1);
                        String fileName = context.getExternalFilesDir(null)
                                .getAbsolutePath() + "/" + imageName;
                        bitmap.compress(CompressFormat.JPEG, 50,
                                new FileOutputStream(fileName));
                        return bitmap;
                    } else {
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                }
            }
        }.execute(imagePath);
    }

    /**
     * 从二级缓存中寻找图片
     *
     * @param imagePath
     *            图片的url
     * @return
     */
    private Bitmap getImageBySecondCache(String imagePath) {
        String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);
        String fileName = context.getExternalFilesDir(null).getAbsolutePath()
                + "/" + imageName;
        return BitmapFactory.decodeFile(fileName);
    }

    /**
     * 从一级缓存中寻找图片
     *
     * @param imagePath
     *            图片的url
     * @return
     */
    private Bitmap getImageByFirstCache(String imagePath) {
        return mapCache.get(imagePath);
    }

}

可以看到这个类的构造方法有三个,第一个是上下文,第二个是加载的图片的时候所显示的图片对应的资源id,第三个是图片加载失败后所显示的图片对应的资源id。

这里有几个关键点:

第一个是在内存缓存中,我们应该使用LruCache来缓存图片,这个类会根据当前所存储的图片空间是否大过设定值,如果比设定值大就会自动释放内存,

这样就能防止内存溢出的问题。

第二个是在使用ListView异步加载图片的时候,并且重用了convertView的时候会导致图片错位的现象。

导致图片错位的根本原因就是重用了convertView。

解决方案如下:

a. 每次getView()都将图片的url保存到ImageView上: imageView.setTag(imagePath)
b. 在分线程准备请求服务器加载图片之前, 比较准备加载图片的url与ImageView中保存的最新图片的url是同一个,
如果不是同一个, 当前加载图片的任务不应该再执行
如果相同, 继续执行加载远程图片
c. 在主线程准备显示图片之前, 比较加载到图片的url与ImageView中保存的最新图片的url是同一个
如果不是同一个, 不需要显示此图片
如果相同, 显示图片

时间: 2024-10-14 18:30:22

安卓网络请求图片到图片的三级缓存技术(内存缓存,本地缓存,网络缓存)的相关文章

网络请求库和图片加载库

网络请求库 概述:所有网络库的原理是: 网络请求一般是基于HttpURLConnection和HttpClient进行封装的,也有自己编写Socket实现的,比如ion和OkHttp:请求的执行一般是通过线程池来管理,异步请求得到结果,则通过回调接口接收:并且一般接收结果的回调都通过Handler去在主线程执行 Ion的使用 详情查看Github主页https://github.com/koush/ion 介绍: 它支持网络请求和进行图片加载的双重功能 拥有链式api风格(Fluent API)

原 Volley框架之网络请求和图片加载

Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架. Volley的特性 (1).封装了的异步的请求API.Volley 中大多是基于接口的设计,可配置性强.(2).一个优雅和稳健的请求队列,一定程度符合 Http 规范,包括请求头的处理,缓存机制的支持等.(3).自定义的网络图像加载视图(NetworkImageView,ImageLoader等) .(4). 提供简便的图片加载工具. 本案例包含get,post请求和几种网络图片加载的方式,效果如图:   

从本地或者网络读取图片,并转换为Bitmap图片

在做android项目时,我们经常需要从本地或者网络读取图片,并转换为Bitmap图片,以便使用,下面是读取本地图片并转换的方法: Java代码   /** * 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如: * * A.网络路径: url="http://blog.foreverlove.us/girl2.png" ; * * B.本地路径:url="file://mnt/sdcard/photo/image.png"; * * 

Android应用中网络请求库Volley的介绍

Volley 是一个HTTP的库,使用它能让Android应用网络传输的操作更加轻松,快捷.Volley的代码是托管在Android 源代码树下的一个工程,编译出来后是一个volley.jar文件.以下是Volley的特点 自动调度在代码中提交的网络请求(http) 多个网络请求的并发执行 对用户透明的磁盘或内存的缓存机制(本质是Http缓存机制) 能够支持网络请求的优先级 能在代码中,必要时轻松的取消网络请求(如activity销毁时),可以取消指定tag的网络请求,或按某种机制分类的网络请求

常见网络请求库汇总

概述: 所有网络库的原理是: 网络请求一般是基于HttpURLConnection和HttpClient进行封装的,也有自己编写Socket实现的,比如ion和OkHttp:请求的执行一般是通过线程池来管理,异步请求得到结果,则通过回调接口接收:并且一般接收结果的回调都通过Handler去在主线程执行 几大网络请求库: Ion:Android Asynchronous Networking and Image Loading Volley:谷歌官方推出的网络请求和图片加载库 Retrofit:S

Volley与XUtils网络请求使用对比,心得,两者基本使用

之前一直使用的Volley作为网络请求框架,它是Google 在2013年的I/O大会 上,发布的.Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,同时扩展性很强.在用它之前我进行了简单的封装,因为Volley默认的请求线程生命周期伴随着Activity的周期,这有时并不能满足项目需要,so上代码: 1 <span style="font-size:14px;"><span style="font-size:14px;&qu

Android网络请求框架 Volley 你所要知道的一切

Volley是2013年谷歌官方推出的Android平台的网络通信库,Volley适用于并发和对效率.性能要求比较高的场景. 1.Volley的特点 优点: (1)使通信更快.更简单 (2)高效的get.post网络请求以及网络图像的高效率异步处理请求 (3)能对网络请求进行排序.优先级处理 (4)网络图片加载和缓存 (5)多级别取消请求,当有多个网络请求同时进行的时候,可以进行同时取消操作 (6)和Activity生命周期的联动,当Activity结束销毁时,可以同时取消网络请求操作 (7)性

队列组用于多个网络请求

dispatch_group_t group = dispatch_group_create(); dispatch_queue_t serialQueue = dispatch_queue_create("com.wzb.test.www", DISPATCH_QUEUE_SERIAL); dispatch_group_enter(group); dispatch_group_async(group, serialQueue, ^{ // 网络请求一 [WebClick getDat

iOS开发——网络请求方法汇总

在实际的项目开发中,连接网络是每一款App必不可少的基本功能.对于客户端的网络请求而言,无非是有两个实现方向:使用网络请求框架或者不使用网络请求框架.在这篇博客中,我将用苹果自带的网络请求方式(不使用第三方框架)下对iOS网络请求方法做一个汇总.我将在之后的博客中介绍使用AFNetworking框架进行请求的实现.代码已经上传至:https://github.com/chenyufeng1991/iOS-NetworkRequest   . [使用XML请求Webservice,可用GET或PO