Android本地缓存和远程图片获取的实现

Android 之 远程图片获取和本地缓存 概述 对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。 另外一 阅读详情
概述
对于客户端——服务器端应 用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量 就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。
另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃。
那么如何处理好图片资源的获取和管理呢?
异步下载
本地缓存
异步下载
大家都知道,在android应用中UI线程5秒没响应的话就会抛出无响应异常,对于远程获取大的资源来说,这种异常还是很容易就会抛出来的,那么怎么避免这种问题的产生。在android中提供两种方法来做这件事情:
启动一个新的线程来获取资源,完成后通过Handler机制发送消息,并在UI线程中处理消息,从而达到在异步线程中获取图片,然后通过Handler Message来更新UI线程的过程。
使用android中提供的AsyncTask来完成。
具体的做法这里就不介绍了,查下API就可以了,或者是google、baidu下。这里主要来说本地缓存。
本地缓存
对于图片资源来说,你不可能让应用每次获取的时候都重新到远程去下载(ListView),这样会浪费资源,但是你又不能让所有图片资源都放到内存 中去(虽然这样加载会比较快),因为图片资源往往会占用很大的内存空间,容易导致OOM。那么如果下载下来的图片保存到SDCard中,下次直接从 SDCard上去获取呢?这也是一种做法,我看了下,还是有不少应用采用这种方式的。采用LRU等一些算法可以保证sdcard被占用的空间只有一小部 分,这样既保证了图片的加载、节省了流量、又使SDCard的空间只占用了一小部分。另外一种做法是资源直接保存在内存中,然后设置过期时间和LRU规 则。
sdcard保存:
在sdcard上开辟一定的空间,需要先判断sdcard上剩余空间是否足够,如果足够的话就可以开辟一些空间,比如10M
当需要获取图片时,就先从sdcard上的目录中去找,如果找到的话,使用该图片,并更新图片最后被使用的时间。如果找不到,通过URL去download
去服务器端下载图片,如果下载成功了,放入到sdcard上,并使用,如果失败了,应该有重试机制。比如3次。
下载成功后保存到sdcard上,需要先判断10M空间是否已经用完,如果没有用完就保存,如果空间不足就根据LRU规则删除一些最近没有被用户的资源。
关键代码:
保存图片到SD卡上
private void saveBmpToSd(Bitmap bm, Stringurl) {
        if (bm == null) {
            Log.w(TAG, " trying to savenull bitmap");
            return;
        }
         //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE >freeSpaceOnSd()) {
            Log.w(TAG, "Low free space onsd, do not cache");
            return;
        }
        String filename =convertUrlToFileName(url);
        String dir = getDirectory(filename);
        File file = new File(dir +"/" + filename);
        try {
            file.createNewFile();
            OutputStream outStream = newFileOutputStream(file);
           bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
            Log.i(TAG, "Image saved tosd");
        } catch (FileNotFoundException e) {
            Log.w(TAG,"FileNotFoundException");
        } catch (IOException e) {
            Log.w(TAG,"IOException");
        }
    }
保存图片到SD卡上
   
    private int freeSpaceOnSd() {
        StatFs stat = newStatFs(Environment.getExternalStorageDirectory() .getPath());
        double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
        return (int) sdFreeMB;
    }修改文件的最后修改时间
   
    private void updateFileTime(String dir,String fileName) {
        File file = new File(dir,fileName);       
        long newModifiedTime =System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }
本地缓存优化
     
    private void removeCache(String dirPath) {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }
        int dirSize = 0;
        for (int i = 0; i < files.length;i++) {
            if(files[i].getName().contains(WHOLESALE_CONV)) {
                dirSize += files[i].length();
            }
        }
        if (dirSize > CACHE_SIZE * MB ||FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            int removeFactor = (int) ((0.4 *files.length) + 1);
            Arrays.sort(files, newFileLastModifSort());
            Log.i(TAG, "Clear some expiredcache files ");
            for (int i = 0; i <removeFactor; i++) {
                if(files[i].getName().contains(WHOLESALE_CONV)) {
                    files[i].delete();
                }
            }
        }
    }
   
    private void removeExpiredCache(StringdirPath, String filename) {
        File file = new File(dirPath,filename);
        if (System.currentTimeMillis() -file.lastModified() > mTimeDiff) {
            Log.i(TAG, "Clear some expiredcache files ");
            file.delete();
        }
    }
文件使用时间排序
classFileLastModifSort implements Comparator<File>{
    public int compare(File arg0, File arg1) {
        if (arg0.lastModified() >arg1.lastModified()) {
            return 1;
        } else if (arg0.lastModified() ==arg1.lastModified()) {
            return 0;
        } else {
            return -1;
        }
    }
}
内存保存:
在内存中保存的话,只能保存一定的量,而不能一直往里面放,需要设置数据的过期时间、LRU等算法。这里有一个方法是把常用的数据放到一个缓存中 (A),不常用的放到另外一个缓存中(B)。当要获取数据时先从A中去获取,如果A中不存在那么再去B中获取。B中的数据主要是A中LRU出来的数据,这 里的内存回收主要针对B内存,从而保持A中的数据可以有效的被命中。1.先定义A缓存:
private final HashMap<String, Bitmap>mHardBitmapCache = new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY/ 2, 0.75f, true) {
        @Override
        protected booleanremoveEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
            if (size() >HARD_CACHE_CAPACITY) {
               //当map的size大于30时,把最近不常用的key放到mSoftBitmapCache中,从而保证mHardBitmapCache的效率
               mSoftBitmapCache.put(eldest.getKey(), newSoftReference<Bitmap>(eldest.getValue()));
                return true;
            } else
                return false;
        }
    };
2.再定于B缓存:
   
    private final staticConcurrentHashMap<String, SoftReference<Bitmap>> mSoftBitmapCache =new ConcurrentHashMap<String,SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);3.从缓存中获取数据:
   
    private Bitmap getBitmapFromCache(Stringurl) {
        // 先从mHardBitmapCache缓存中获取
        synchronized (mHardBitmapCache) {
            final Bitmap bitmap =mHardBitmapCache.get(url);
            if (bitmap != null) {
                //如果找到的话,把元素移到linkedhashmap的最前面,从而保证在LRU算法中是最后被删除
                mHardBitmapCache.remove(url);
                mHardBitmapCache.put(url,bitmap);
                return bitmap;
            }
        }
        //如果mHardBitmapCache中找不到,到mSoftBitmapCache中找
        SoftReference<Bitmap>bitmapReference = mSoftBitmapCache.get(url);
        if (bitmapReference != null) {
            final Bitmap bitmap =bitmapReference.get();
            if (bitmap != null) {
                return bitmap;
            } else {
                mSoftBitmapCache.remove(url);
            }
        }
        return null;
    }4.如果缓存中不存在,那么就只能去服务器端去下载:
   
    class ImageDownloaderTask extendsAsyncTask<String, Void, Bitmap> {
        private static final int IO_BUFFER_SIZE= 4 * 1024;
        private String url;
        private finalWeakReference<ImageView> imageViewReference;
        public ImageDownloaderTask(ImageViewimageView) {
            imageViewReference = newWeakReference<ImageView>(imageView);
        }       @Override
        protected BitmapdoInBackground(String... params) {
            final AndroidHttpClient client =AndroidHttpClient.newInstance("Android");
            url = params[0];
            final HttpGet getRequest = newHttpGet(url);
            try {
                HttpResponse response =client.execute(getRequest);
                final int statusCode =response.getStatusLine().getStatusCode();
                if (statusCode !=HttpStatus.SC_OK) {
                    Log.w(TAG, "从" +url + "中下载图片时出错!,错误码:" + statusCode);
                    return null;
                }
                final HttpEntity entity =response.getEntity();
                if (entity != null) {
                    InputStream inputStream =null;
                    OutputStream outputStream =null;
                    try {
                        inputStream =entity.getContent();
                        finalByteArrayOutputStream dataStream = new ByteArrayOutputStream();
                        outputStream = newBufferedOutputStream(dataStream, IO_BUFFER_SIZE);
                        copy(inputStream,outputStream);
                        outputStream.flush();
                        final byte[] data =dataStream.toByteArray();
                        final Bitmap bitmap =BitmapFactory.decodeByteArray(data, 0, data.length);
                        return bitmap;
                    } finally {
                        if (inputStream !=null) {
                           inputStream.close();
                        }
                        if (outputStream !=null) {
                           outputStream.close();
                        }
                       entity.consumeContent();
                    }
                }
            } catch (IOException e) {
                getRequest.abort();
                Log.w(TAG, "I/O errorwhile retrieving bitmap from " + url, e);
            } catch (IllegalStateException e) {
                getRequest.abort();
                Log.w(TAG, "Incorrect URL:" + url);
            } catch (Exception e) {
                getRequest.abort();
                Log.w(TAG, "Error whileretrieving bitmap from " + url, e);
            } finally {
                if (client != null) {
                    client.close();
                }
            }
            return null;
        }
这是两种做法,还有一些应用在下载的时候使用了线程池和消息队列MQ,对于图片下载的效率要更好一些。有兴趣的同学可以看下。
总结
对于远程图片等相对比较大的资源一定要在异步线程中去获取
本地做缓存

Android远程图片获取和本地缓存   异步下载   本地缓存   异步下载   大家都知道,在android应用中UI线程5秒没响应的话就会抛出无响应异常,对于远程获取大的资源来说,这种异常还是很容易就会抛出来的,那么怎么避免这种问题的产生。在android中提供两种方法来做这件事情: 立即下载

相关推荐

html5实现页面的显示本地图片

file标签,多选图片,然后图片显示在页面,使用html5 file api

Android之远程图片获取和本地缓存

概述对于客户端——服务器端应 用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量 就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃。那么如何处理好图片资源的获取和管理呢?异步下载本...

weixin_33895016的博客 150

抖音短视频数据抓取实战系列(一)——模拟器性能对比与优化配置

本文是抖音短视频数据抓取实战系列的开篇,重点探讨了模拟器选型与优化配置。通过对比雷电、夜神、逍遥三大主流模拟器在性能、抖音兼容性及抓包友好度上的表现,文章指出雷电模拟器因其稳定的桥接网络模式和良好的兼容性,是数据抓取的优选。并提供了雷电模拟器从安装、网络桥接到系统优化的详细配置指南,旨在帮助读者构建稳定高效的抓取环境。

weixin_29230901的博客 244

xamarin 加载图片

加载图片 下载映像 可以自动下载图像以进行显示,如下面的 XAML 所示: XAML 复制 等效的 c # 代码如下所示: C# 复制 var webImage = new Image { Source = ImageSource.FromUri( new Uri(“https://aka.ms/campus.jpg”) ) }; ImageSource.FromUri方法需要一个 Uri 对象,并返回一个 UriImageSource 从中读取的新 Uri 。 还存在对 URI 字符串的隐式

qq_42526332的博客 544

proteus仿真51单片机操作指南:串口通信仿真配置详解

深入讲解如何在proteus仿真51单片机中实现串口通信,涵盖虚拟串口设置、电路连接与调试技巧,帮助开发者高效完成通信仿真验证。

weixin_36197669的博客 569

铭飞MCMS源码部署

文章目录前言一、下载铭飞源码二、部署源码1.使用IDEA打开源码2.配置tomcat环境2.1下载tomcat并测试是否可以成功启动(此处不赘述)2.2在IDEA中安装tomcat环境并配置3.添加数据库,并配置3.1新建数据库3.2 导入sql配置三、启动测试 前言 铭飞MCMS基于IDEA、tomcat和mysql的环境搭建。 提示:以下是本篇文章正文内容,下面案例可供参考 一、下载铭飞源码 gitee:https://gitee.com/mingSoft/MCMS/releases(各种版本按需下

MARS_ZORO的博客 4062

Android 获取远程图片与本地图片缓存

1.意义:加快读取速度,减少流量的消耗,减少崩溃的次数 2.Android应用中的UI现成5秒没有相应的话就会强制抛出异常,俗称ANR(Appliction Not Responce),对于获取远程的资源,这里特指的是从服务器获取的数据譬如图片等等,这种异常将会更加容易被抛出来,所以在Android 4.0 里面将限制了网络的访问,不允许将网络的访问放在主线程,低于4.0的版本就不会收到限制

long704480904 4499

YOLOv5实战:无人机巡检图片差异对比与违建标记(附完整代码)

本文详细介绍了如何利用YOLOv5目标检测技术实现无人机巡检图片差异对比与违建标记。通过图像对齐、目标检测、差异分析和可视化标记四个步骤,构建高效的违建识别系统,显著提升城市管理效率。文章包含完整代码实现和性能优化技巧,为计算机视觉在无人机巡检中的应用提供实用指南。

weixin_42535720的博客 280

android 如何显示网络地址对应的图片

android 如何显示网络地址对应的图片

xie__jin__cheng的博客 1463

CST 2023安装避坑指南:从下载到破解的完整流程(附常见报错解决方案)

本文提供CST 2023三维全波电磁场仿真软件的完整安装指南,涵盖从下载到破解的全流程,并附常见报错解决方案。详细解析安装步骤、许可证配置优化及高频问题诊断,帮助用户快速部署并优化软件性能,适用于射频电路设计、天线优化等场景。

7z8x2c4v6b9的博客 656

高功率半导体叠阵激光快慢轴准直优化技术解析

本文深入解析了高功率半导体叠阵激光快慢轴准直优化技术。针对其光束发散特性,文章系统阐述了从光源建模、光学仿真到透镜选型与参数匹配的完整工程流程,并强调了光束整形对于提升加工精度与效率的核心作用。通过优化快慢轴准直,可将原始散光转变为能量集中、均匀性好的高质量光束,为后续工业应用奠定基础。

php55的博客 713

android缓存图片,Android 图片缓存

前言本篇主要包含两个方面的内容:图片的加载和优化图片的加载LruCache,DisLruCache的使用与图片的三级缓存图片的加载和优化我们在编写Android程序的时候经常要用到很多的图片,在大多数情况下,这些图片都会大于我们程序所需要的大小。我们编写的应用程序都是有一定的内存限制,程序占用了过高的内存就容易出现OOM(Out Of Memory)异常。如下代码可以看出每个应用程序最高可用内存:...

weixin_34766430的博客 612

Python爬虫实战:5分钟搞定微信公众号文章阅读数、点赞数抓取(附完整代码)

本文详细介绍了如何通过Python爬虫技术自动化抓取微信公众号文章的阅读数和点赞数。文章从数据源分析入手,分步讲解了获取文章列表与提取单篇统计数据的完整流程,并提供了应对平台风控的策略与工程化整合方案,帮助开发者高效、合规地完成数据采集任务。

ansible6ops的博客 1332

android-远程图片获取和本地缓存

概述 对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。 另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃。 那么如何处理好图片资源的获取和管理呢:异...

weixin_33830216的博客 102

【RT-DETR实战】159、改进九:知识蒸馏从YOLOv8教师模型学习

摘要: 本文探讨了知识蒸馏在RT-DETR目标检测模型中的应用挑战与实践经验。作者以YOLOv8作为教师模型,针对特征对齐、损失函数设计和训练策略等核心问题,提出了适配器模块、动态权重调整和多阶段训练等优化方案。文章重点分析了教师模型选择、特征图匹配、损失函数组合等关键环节的实战技巧,并总结了蒸馏模型部署时的注意事项。通过实验验证,作者指出知识蒸馏应关注模型"思维方式"的迁移而非简单特征复制,并强调合理评估指标和教师模型选择的重要性。最后,作者分享了技术迭代中的边际效应认知,为工业场景下的模型优化提供了实用

企鹅码农的专属播客,分享10多年的实战案例和经验解读,包含YOLO、RT-DETR、AI等各个工作领域。 268

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

android远程更改图片大小,Android远程获取图片并本地缓存

对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃。那么如何处理好图片资源的获取和管理呢?*异步下载*本地缓...

weixin_27743991的博客 138

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android加载图片出现内存溢出攻略

转http://www.cnblogs.com/zgz345/archive/2013/01/06/2848024.html

hkp574305834的专栏 258

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

图片下载工具类:BitmapUtil

package com.net.util;      import java.io.File;   import java.io.FileOutputStream;   import java.io.IOException;   import java.io.InputStream;   import java.net.HttpURLConnection;   import java

qq_24954199的博客 732

android开发架构设计学习

[img]http://dl.iteye.com/upload/attachment/601616/8a3d7a6d-7882-3a7f-b451-ea3178e35e48.png[/img] [url=http://mobile.51cto.com/android-288600.htm]Android远程图片获取和本地缓存[/url] [url=http://www.cnblogs.co...

喧嚣求静 104

android 远程图片获取和本地缓存

概述 对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运。 另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃。 那么如何处理好图片资源的获取和管理呢? A

写博客只为学习 879
上一篇: Android 图片缓存
下一篇: 程序员编程技术迅速提高的终极攻略
llyofdream
博客等级 码龄16年 74粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值