位置: 编程技术 - 正文

Android照片墙完整版,完美结合LruCache和DiskLruCache(照片墙安装教程)

编辑:rootadmin

推荐整理分享Android照片墙完整版,完美结合LruCache和DiskLruCache(照片墙安装教程),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:照片墙手机软件,照片墙应用下载,android 照片墙,手机照片墙设计软件,照片墙手机软件,手机照片墙设计软件,照片墙手机软件,android 照片墙,内容如对您有帮助,希望把文章链接给更多的朋友!

转载请注明出处: Android DiskLruCache完全解析,硬盘缓存的最佳方案 。

其实,在真正的项目实战当中如果仅仅是使用硬盘缓存的话,程序是有明显短板的。而如果只使用内存缓存的话,程序当然也会有很大的缺陷。因此,一个优秀的程序必然会将内存缓存和硬盘缓存结合到一起使用,那么本篇文章我们就来看一看,如何才能将LruCache和DiskLruCache完美结合到一起。

在 Android照片墙应用实现,再多的图片也不怕崩溃 这篇文章当中,我编写了一个照片墙的应用程序,但当时只是单纯使用到了内存缓存而已,而今天我们就对这个例子进行扩展,制作一个完整版的照片墙。

那我们开始动手吧,新建一个Android项目,起名叫PhotoWallDemo,这里我使用的是Android 4.0的API。然后新建一个libcore.io包,并将DiskLruCache.java文件拷贝到这个包下,这样就把准备工作完成了。

接下来首先需要考虑的仍然是图片源的问题,简单起见,我仍然是吧所有图片都上传到了我的CSDN相册当中,然后新建一个Images类,将所有相册中图片的网址都配置进去,代码如下所示:

[java] view plaincopypublic class Images { public final static String[] imageThumbUrls = new String[] { " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " }; } 设置好了图片源之后,我们需要一个GridView来展示照片墙上的每一张图片。打开或修改activity_main.xml中的代码,如下所示:[html] view plaincopy<LinearLayout xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" > <GridView android:id="@&#;id/photo_wall" android:layout_width="match_parent" android:layout_height="match_parent" android:columnWidth="@dimen/image_thumbnail_size" android:gravity="center" android:horizontalSpacing="@dimen/image_thumbnail_spacing" android:numColumns="auto_fit" android:stretchMode="columnWidth" android:verticalSpacing="@dimen/image_thumbnail_spacing" > </GridView> </LinearLayout> 很简单,只是在LinearLayout中写了一个GridView而已。接着我们要定义GridView中每一个子View的布局,新建一个photo_layout.xml布局,加入如下代码:[html] view plaincopy<RelativeLayout xmlns:android=" xmlns:tools=" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@&#;id/photo" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:scaleType="fitXY" /> </RelativeLayout> 仍然很简单,photo_layout.xml布局中只有一个ImageView控件,就是用它来显示图片的。这样我们就把所有的布局文件都写好了。

接下来新建PhotoWallAdapter做为GridView的适配器,代码如下所示:

[java] view plaincopypublic class PhotoWallAdapter extends ArrayAdapter<String> { /** * 记录所有正在下载或等待下载的任务。 */ private Set<BitmapWorkerTask> taskCollection; /** * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定&#;时会将最少最近使用的图片移除掉。 */ private LruCache<String, Bitmap> mMemoryCache; /** * 图片硬盘缓存核心类。 */ private DiskLruCache mDiskLruCache; /** * GridView的实例 */ private GridView mPhotoWall; /** * 记录每个子项的高度。 */ private int mItemHeight = 0; public PhotoWallAdapter(Context context, int textViewResourceId, String[] objects, GridView photoWall) { super(context, textViewResourceId, objects); mPhotoWall = photoWall; taskCollection = new HashSet<BitmapWorkerTask>(); // 获取应用程序最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; // 设置图片缓存大小为程序最大可用内存的1/8 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount(); } }; try { // 获取图片缓存路径 File cacheDir = getDiskCacheDir(context, "thumb"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } // 创建DiskLruCache实例,初始化缓存数据 mDiskLruCache = DiskLruCache .open(cacheDir, getAppVersion(context), 1, * * ); } catch (IOException e) { e.printStackTrace(); } } @Override public View getView(int position, View convertView, ViewGroup parent) { final String url = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null); } else { view = convertView; } final ImageView imageView = (ImageView) view.findViewById(R.id.photo); if (imageView.getLayoutParams().height != mItemHeight) { imageView.getLayoutParams().height = mItemHeight; } // 给ImageView设置一个Tag,保证异步加载图片时不会乱序 imageView.setTag(url); imageView.setImageResource(R.drawable.empty_photo); loadBitmaps(imageView, url); return view; } /** * 将一张图片存储到LruCache中。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @param bitmap * LruCache的键,这里传入从网络上下载的Bitmap对象。 */ public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemoryCache(key) == null) { mMemoryCache.put(key, bitmap); } } /** * 从LruCache中获取一张图片,如果不存在就返回null。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @return 对应传入键的Bitmap对象,或者null。 */ public Bitmap getBitmapFromMemoryCache(String key) { return mMemoryCache.get(key); } /** * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象, * 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。 */ public void loadBitmaps(ImageView imageView, String imageUrl) { try { Bitmap bitmap = getBitmapFromMemoryCache(imageUrl); if (bitmap == null) { BitmapWorkerTask task = new BitmapWorkerTask(); taskCollection.add(task); task.execute(imageUrl); } else { if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); } } } catch (Exception e) { e.printStackTrace(); } } /** * 取消所有正在下载或等待下载的任务。 */ public void cancelAllTasks() { if (taskCollection != null) { for (BitmapWorkerTask task : taskCollection) { task.cancel(false); } } } /** * 根据传入的uniqueName获取硬盘缓存的路径地址。 */ public File getDiskCacheDir(Context context, String uniqueName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath &#; File.separator &#; uniqueName); } /** * 获取当前应用程序的版本号。 */ public int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; } /** * 设置item子项的高度。 */ public void setItemHeight(int height) { if (height == mItemHeight) { return; } mItemHeight = height; notifyDataSetChanged(); } /** * 使用MD5算法对传入的key进行加密并返回。 */ public String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } /** * 将缓存记录同步到journal文件中。 */ public void fluchCache() { if (mDiskLruCache != null) { try { mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } } private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i&#;&#;) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } /** * 异步下载图片的任务。 * * @author guolin */ class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { /** * 图片的URL地址 */ private String imageUrl; @Override protected Bitmap doInBackground(String... params) { imageUrl = params[0]; FileDescriptor fileDescriptor = null; FileInputStream fileInputStream = null; Snapshot snapShot = null; try { // 生成图片URL对应的key final String key = hashKeyForDisk(imageUrl); // 查找key对应的缓存 snapShot = mDiskLruCache.get(key); if (snapShot == null) { // 如果没有找到对应的缓存,则准备从网络上请求数据,并写入缓存 DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); if (downloadUrlToStream(imageUrl, outputStream)) { editor.commit(); } else { editor.abort(); } } // 缓存被写入后,再次查找key对应的缓存 snapShot = mDiskLruCache.get(key); } if (snapShot != null) { fileInputStream = (FileInputStream) snapShot.getInputStream(0); fileDescriptor = fileInputStream.getFD(); } // 将缓存数据解析成Bitmap对象 Bitmap bitmap = null; if (fileDescriptor != null) { bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); } if (bitmap != null) { // 将Bitmap对象添加到内存缓存当中 addBitmapToMemoryCache(params[0], bitmap); } return bitmap; } catch (IOException e) { e.printStackTrace(); } finally { if (fileDescriptor == null && fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { } } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); // 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。 ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl); if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); } taskCollection.remove(this); } /** * 建立HTTP请求,并获取Bitmap对象。 * * @param imageUrl * 图片的URL地址 * @return 解析后的Bitmap对象 */ private boolean downloadUrlToStream(String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), 8 * ); out = new BufferedOutputStream(outputStream, 8 * ); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final IOException e) { e.printStackTrace(); } } return false; } } }

代码有点长,我们一点点进行分析。首先在PhotoWallAdapter的构造函数中,我们初始化了LruCache类,并设置了内存缓存容量为程序最大可用内存的1/8,紧接着调用了DiskLruCache的open()方法来创建实例,并设置了硬盘缓存容量为M,这样我们就把LruCache和DiskLruCache的初始化工作完成了。

接着在getView()方法中,我们为每个ImageView设置了一个唯一的Tag,这个Tag的作用是为了后面能够准确地找回这个ImageView,不然异步加载图片会出现乱序的情况。然后在getView()方法的最后调用了loadBitmaps()方法,加载图片的具体逻辑也就是在这里执行的了。

进入到loadBitmaps()方法中可以看到,实现是调用了getBitmapFromMemoryCache()方法来从内存中获取缓存,如果获取到了则直接调用ImageView的setImageBitmap()方法将图片显示到界面上。如果内存中没有获取到,则开启一个BitmapWorkerTask任务来去异步加载图片。

那么在BitmapWorkerTask的doInBackground()方法中,我们就灵活运用了上篇文章中学习的DiskLruCache的各种用法。首先根据图片的URL生成对应的MD5 key,然后调用DiskLruCache的get()方法来获取硬盘缓存,如果没有获取到的话则从网络上请求图片并写入硬盘缓存,接着将Bitmap对象解析出来并添加到内存缓存当中,最后将这个Bitmap对象显示到界面上,这样一个完整的流程就执行完了。

Android照片墙完整版,完美结合LruCache和DiskLruCache(照片墙安装教程)

那么我们再来分析一下上述流程,每次加载图片的时候都优先去内存缓存当中读取,当读取不到的时候则回去硬盘缓存中读取,而如果硬盘缓存仍然读取不到的话,就从网络上请求原始数据。不管是从硬盘缓存还是从网络获取,读取到了数据之后都应该添加到内存缓存当中,这样的话我们下次再去读取图片的时候就能迅速从内存当中读取到,而如果该图片从内存中被移除了的话,那就重复再执行一遍上述流程就可以了。

这样我们就把LruCache和DiskLruCache完美结合到一起了。接下来还需要编写MainActivity的代码,非常简单,如下所示:

[java] view plaincopypublic class MainActivity extends Activity { /** * 用于展示照片墙的GridView */ private GridView mPhotoWall; /** * GridView的适配器 */ private PhotoWallAdapter mAdapter; private int mImageThumbSize; private int mImageThumbSpacing; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageThumbSize = getResources().getDimensionPixelSize( R.dimen.image_thumbnail_size); mImageThumbSpacing = getResources().getDimensionPixelSize( R.dimen.image_thumbnail_spacing); mPhotoWall = (GridView) findViewById(R.id.photo_wall); mAdapter = new PhotoWallAdapter(this, 0, Images.imageThumbUrls, mPhotoWall); mPhotoWall.setAdapter(mAdapter); mPhotoWall.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { final int numColumns = (int) Math.floor(mPhotoWall .getWidth() / (mImageThumbSize &#; mImageThumbSpacing)); if (numColumns > 0) { int columnWidth = (mPhotoWall.getWidth() / numColumns) - mImageThumbSpacing; mAdapter.setItemHeight(columnWidth); mPhotoWall.getViewTreeObserver() .removeGlobalOnLayoutListener(this); } } }); } @Override protected void onPause() { super.onPause(); mAdapter.fluchCache(); } @Override protected void onDestroy() { super.onDestroy(); // 退出程序时结束所有的下载任务 mAdapter.cancelAllTasks(); } } 上述代码中,我们通过getViewTreeObserver()的方式监听View的布局事件,当布局完成以后,我们重新修改一下GridView中子View的高度,以保证子View的宽度和高度可以保持一致。

到这里还没有结束,最后还需要配置一下AndroidManifest.xml文件,并加入相应的权限,如下所示:

[html] view plaincopy<manifest xmlns:android=" package="com.example.photoswalldemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="" android:targetSdkVersion="" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.photoswalldemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

好了,全部代码都在这儿了,让我们来运行一下吧,效果如下图所示:

第一次从网络上请求图片的时候有点慢,但之后加载图片就会非常快了,滑动起来也很流畅。

那么我们最后再检查一下这些图片是不是已经正确缓存在指定地址了,进入 /sdcard/Android/data/<application package>/cache/thumb 这个路径,如下图所示:

可以看到,每张图片的缓存以及journal文件都在这里了,说明我们的硬盘缓存已经成功了。

好了,今天的讲解就到这里,有疑问的朋友可以在下面留言。

源码下载,请点击这里

Android导入现有的数据库 常用的路径写法获取/system路径Environment.getRootDirectory();获取/cache路径Environment.getDownloadCacheDirectory();获取当前程序路径context.getFilesDir().getAbsolutePath();获取

如何解决Android SDK中离线文档打开慢的问题 转自:

高级控件AdapterView(二):通过Observer实现数据、视图同步刷新 多条目控件AdapterView是仿MVC设计模式进行设计的,即AdapterView与数据是分离的,AdapterView并不直接操作数据,而是利用中间件适配器Adapter,实际上,完整

标签: 照片墙安装教程

本文链接地址:https://www.jiuchutong.com/biancheng/370978.html 转载请保留说明!

上一篇:打开app后Edittext自动获取焦点并弹出输入法的方法(edit apps)

下一篇:Android导入现有的数据库(android如何导入文件)

  • 为什么要交税钱
  • 报销单与发票金额不符
  • 本币原值是什么意思
  • 合同每三个月付一次款
  • 公司名称房产和房地产区别
  • 金蝶怎么填写凭证
  • 计算并分摊本月利润
  • 公司租用办公室需要交房产税吗
  • 企业零申报怎么申报
  • 流动负债中的短期借款
  • 货物尾款优惠如何计算
  • 未分配利润如何使用投入生产
  • 公允价值变动损益会计处理
  • 母公司代子公司付款合法吗
  • 现金日记账的登记依据有
  • 企业法人投资股4 账户
  • 企业所得税根据什么报表申报
  • 外地建安个人所得税标准
  • 转让专利技术使用权属于销售无形资产吗
  • 药企会计租金进项税不能抵扣
  • 质量成本包括哪两个成本
  • 本期认证本期不抵扣下月再抵扣
  • 电器以旧换新的套路
  • 会展企业的作用有哪些
  • 一般纳税人税控盘维护费会计分录
  • 广告公司固定资产有哪些?
  • 外地预缴工会其他经费计入什么科目?
  • 结转完工产品成本的计算
  • pps影音怎么看电视直播
  • encodetext
  • 判断企业存货过多的判断方法
  • lsalss.exe
  • 个体工商户筹集资金的难易程度
  • 房屋无偿赠与合同协议书范本
  • maven视频教程
  • 利润总额为负还交所得税吗
  • 什么是技术服务工程师
  • 总部资产减值测试例题
  • 一般纳税人取得普票会计分录
  • gridview datakeynames
  • 一般纳税人使用的是什么会计准则
  • 凭证怎么记账
  • uniapp自定义导航栏渐变
  • css伪类选择器怎么用
  • 年末应交税费怎么算
  • 招待费的进项税必须认证后转出吗
  • 合伙企业个人所得税怎么算
  • php怎么修改当前用户的密码
  • mongodb 权限设置
  • 单一窗口报关是指什么
  • 销售清单有法律效力吗
  • 企业会计准则在建工程转固定资产
  • sqlserver 数据库加密
  • 盘亏的设备要进仓库吗
  • 发票抬头开个人可以吗?
  • 移动怎么开当月发票
  • 代扣代缴公积金现金流量
  • 2018年小规模纳税人
  • 计提应付款是什么意思
  • 销售材料购买方会计分录
  • 成本不够如何计算出来
  • 公司与公司之间劳务协议
  • 汽车贷款利息计算公式计算器
  • 私营公司无形资产怎么算
  • 使用筷子就餐会不会传染乙肝病毒
  • win10玩魔兽争霸卡顿
  • winadslave.exe - winadslave是什么进程
  • RunClubSanDisk.exe是什么程序? 闪迪U盘广告推介程序
  • LINUX下的磁盘编辑工具
  • 360对win7支持多久
  • ie等级
  • 微信小程序实现微信支付
  • 最简单的游戏开发工具
  • linux怎么安装rz
  • 常用的批处理文件
  • cocos2d怎么用
  • jquery元素选择器有哪些
  • 税务工作意见和建议
  • 日本各界
  • 年度汇算清缴计算
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设