android照片墙应用技巧。

照片墙应用介绍

应用中需要显示大量的图片,图片从网络获取。

应用有两个问题:

流畅地显示

省流量

流畅性是所有应用都必须要有的,图片要从网上下载,下载过程必须放到工作线程当中来解决。另外图片也有可以有一部分保存在内存当中,直接从内存当中获取并显示,这才是最快的方式。

图片有很多,用户理论上只用下载一遍图片就行了,不能重复去下载,缓存可以帮助用户节省流量。

缓存使用思路

android 缓存原理一文中说明了缓存的原理以及使用方式,如有不明白可参考此文。

其实缓存思路特别简单,在需要使用图片的时候,先查内存缓存,如果没有再查硬盘缓存,还没有则去网络下载,下载完毕后加入硬盘缓存以及内存缓存,以备下次再用。缓存是不是已满,该如何删除交给缓存工具类决定,但大体思路一定是这样。

本文中也是这么做的,而且硬盘缓存读取相当于io过程,较缓慢,也可以放到工作线程当中,于是就可以把查内存缓存以外的所有操作都放到工作线程当中完成。

照片墙的核心代码如下:

privatevoidloadbitmaps(imageviewimageview,stringurl){

try{

bitmapbitmap=getbitmapfrommemorycache(url);

if(bitmap==null){

tasktask=newtask(imageview,url);

mpools.submit(task);

}else{

if(imageview!=null&&bitmap!=null){

imageview.setimagebitmap(bitmap);

}

}

}catch(exceptione){

//todo:handleexception

}

}

如果从内存缓存中无法获取到图片,则向线程池中提交一个任务,在线程池中完成图片的获取。

classtaskimplementsrunnable{

imageviewiv;

stringimageurl;

task(imageviewview,stringurl){

iv=view;

imageurl=url;

}

@override

publicvoidrun(){

filedescriptorfiledescriptor=null;

fileinputstreamfileinputstream=null;

snapshotsnapshot=null;

try{

finalstringkey=hashkeyfordisk(imageurl);

snapshot=mdisklrucache.get(key);

if(snapshot==null){

editoreditor=mdisklrucache.edit(key);

if(editor!=null){

outputstreamoutputstream=editor.newoutputstream(0);

if(downloadurltostream(imageurl,outputstream)){

editor.commit();

}else{

editor.abort();

}

}

snapshot=mdisklrucache.get(key);

}

if(snapshot!=null){

fileinputstream=(fileinputstream)snapshot

.getinputstream(0);

filedescriptor=fileinputstream.getfd();

}

bitmapbitmap=null;

if(filedescriptor!=null){

bitmap=bitmapfactory.decodefiledescriptor(filedescriptor);

}

if(bitmap!=null){

addbitmaptomemorycache(key,bitmap);

resultresult=newresult(iv,bitmap,imageurl);

messagemsg=message.obtain(mhandler,msg_show_bitmap,result);

msg.sendtotarget();

}

}catch(exceptione){

log.e("okunu","run",e);

}

}

}

和前文所说思路一样,先从硬盘缓存中读取,如果没有再从网络中下载图片。一定不能忘记将图片添加进入硬盘缓存和内存缓存中来,这一步非常重要。

由于硬盘缓存的使用方法,在从网上下载图片的时候,是直接下载到缓存文件当中的,而不是先下载再复制一份到硬盘缓存当中,因为这样可以节省一次io过程。

另外还有一些小细节,比如最后如何刷新界面,首先在工作线程中是无法刷新ui的,所以在此处用handler,将结果返回主线程中处理。

if(msg.what==msg_show_bitmap){

objectobj=msg.obj;

if(obj!=null){

resultresult=(result)obj;

if(result.iv.gettag().equals(result.url)){

result.iv.setimagebitmap(result.bitmap);

}

}

}

结果中包含图片、imageview以及url,为了防止图片显示错乱,还加以判定,只有imageview的tag等于此url的时候,才更新图片,如此则不会更新错乱。

多线程使用

在这种有大量耗时操作的时候,开启工作线程是非常必要的,但如何优雅地使用线程,其实仍然有门道。

android中有很多种开启工作线程的方式。

asynctask,封装地非常好,不同的回调函数还处于不同的线程当中,方便用户拿结果更新ui,但如果有多个asynctask实例在执行,它们是顺序执行,并不是想象中的多线程在多核cpu上同时执行。

thread,原始的线程使用方式,如果构造太多,不优雅,线程不能得到复用,浪费资源,开启一个线程也是有开销的

handlerthread,能够与handler结合,一种非常优雅的工作线程开启方式,不过不太适合大量任务的情况,这种只相当于线程池中只有一个线程在跑

线程池,重量级武器,适合大量任务的情况

android中开启工作线程包括但不限于以上4种,它们的优劣大致如上所述,需要我们根据不同的情形选用不同的方式,写出优雅的代码。

在照片墙应用中,明显是有大量任务需要工作线程来执行的,以上四种情况中,最适合的就是线程池了,它的速度效率是最高的,有兴趣的同学可以去做做实验,以四种不同方式来完成任务,看看哪个效率最高

杂谈

在文章一开始的时候,就聊到一个话题,oom的问题,如果图片太大,如果防止oom呢

这个问题相信很多人都知道答案:

/**

*ifsettotrue,thedecoderwillreturnnull(nobitmap),but

*theout...fieldswillstillbeset,allowingthecallerto

*querythebitmapwithouthavingtoallocatethememoryforitspixels.

*/

publicbooleaninjustdecodebounds;

/**

*ifsettoavalue>1,requeststhedecodertosubsampletheoriginal

*image,returningasmallerimagetosavememory.thesamplesizeis

*thenumberofpixelsineitherdimensionthatcorrespondtoasingle

*pixelinthedecodedbitmap.forexample,insamplesize==4returns

*animagethatis1/4thewidth/heightoftheoriginal,and1/16the

*numberofpixels.anyvalue<=1istreatedthesameas1.note:the

*decoderusesafinalvaluebasedonpowersof2,anyothervaluewill

*beroundeddowntothenearestpowerof2.

*/

publicintinsamplesize;

利用injustdecodebounds,计算出insamplesize,相信这样的逻辑网上一找一大堆,本人在此不再复述。如果你的图片应用,图片都是大于5m以上的高清大图,那么一定要考虑这个方法了。

另外由url转化成hash key的时候,怎么这么费劲呢

publicstringhashkeyfordisk(stringkey){

stringcachekey;

try{

finalmessagedigestmdigest=messagedigest.getinstance("md5");

mdigest.update(key.getbytes());

cachekey=bytestohexstring(mdigest.digest());

log.i("okunu","cachekey="+cachekey);

}catch(nosuchalgorithmexceptione){

cachekey=string.valueof(key.hashcode());

}

returncachekey;

}

privatestringbytestohexstring(byte[]bytes){

stringbuildersb=newstringbuilder();

for(inti=0;istringhex=integer.tohexstring(0xff&bytes[i]);

if(hex.length()==1){

sb.append('0');

}

sb.append(hex);

}

returnsb.tostring();

}

第一步,我们通常能理解,获取url的md5值,因为url中可能含有各种奇异字符,不适合作为key来使用,但bytestohexstring方法的作用是什么

大家可以仔细地看看硬盘缓存中文件的名字的长度,就是为了防止名字长度不一致,当长度短一位的时候,补0。

代码已经上传到github当中,有需要的可以取用

https://github.com/okunu

照片处理

android 选择图片上传功能【支持多选拍照预览等】

android+照片墙流布局,Android照片墙应用技巧相关推荐

  1. android手机不显示照片墙,手机照片墙如何设置

    我们经常看到我们QQ好友里边有的朋友设置了手机 照片墙 ,而且手机照片墙的照片还经常变化,各种时间各种地点各种心情别人随时随地可以知晓,非常方便也很好玩,那么,我们怎么才能将它们设置成手机照片墙呢!今 ...

  2. android短信功能裁剪,Android短信发送功能实现技巧分享

    如现在启动一模拟器id 号为5554,运行cmd telnet localhost 5554 输入help 可以看到很多用于模拟器中的功能命令 gsm call 134343434   // 便是呼叫 ...

  3. 10种可提升Android应用程序运行效果的技巧

    技巧1:从优秀的编程开始 要采用已为用户所接受的运算法则和标准的设计样式,这些被人们长期使用的编程法则也同样适用于Android应用,尤其当这些应用使用内在设备服务时. 比如,假设你编写的应用需要以地 ...

  4. Android中的资源复用小技巧

    前言 做了很多项目,发现每个项目里都有大量的相似图标,比如每个颜色一种.每个角度一种(左箭头.右箭头)等等,虽然这些图标很小占用不了太多资源.但是当我们需要change的时候就得一个个去替换,其实在a ...

  5. Android Coding利器之掌握小技巧,助你Coding更上一层楼~

    本文讲的是Android Coding利器之掌握小技巧,助你Coding更上一层楼~,话说前几天在网上浏览到一大牛写的关于Android布局优化的文章,看后感触很深,回过头看看自己写过的代码,发现还是 ...

  6. Android 应用开发---Android状态栏微技巧

    Android状态栏微技巧,带你真正理解沉浸式模式 其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的.因为Android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模 ...

  7. java列表展开折叠,Android在开发中的实用技巧之ExpandableListView简单实现商品列表折叠...

    根据已上线的app里总结出来的实用小技巧 一.简介 在日常开发,有可能会遇到需要一些可以展开的列表,比如QQ的好友列表.但是,用Android的该怎么做呢?其实在我没有接触过ExpandableLis ...

  8. android壁纸和手机屏幕之间要怎么对应,安卓Android手机屏幕壁纸分辨率选择技巧...

    安卓Android手机屏幕壁纸分辨率选择技巧 现在使用安卓手机的人好多了,一个好的手机壁纸自然是大家的追求,那么要怎么挑选适合自己安卓手机的手机壁纸呢~登博教程小编来教你挑选吧~ 大家先看看对应的壁纸 ...

  9. 浅析Android中build.gradle的实用技巧

    1.替换符的使用 (1)在 app-android-defaultConfig (或者多渠道打包)下面可以这样使用 android {defaultConfig {manifestPlaceholde ...

最新文章

  1. 经典PV操作问题 [转]
  2. 无线信标功能调试-2021-3-9-HALL检测与主控接口
  3. openfire 插件开发
  4. DataGridView控件60招(一)
  5. python编写程序-30分钟学会用Python编写简单程序
  6. html标签table的使用,HTML标签之table
  7. vivo Y66的usb调试模式在哪里,打开vivo Y66usb调试模式的流程
  8. MSP430程序库二UART异步串口
  9. 20201125:力扣第216场周赛(下)
  10. python赋值标志_Python中的赋值、引用和深浅拷贝
  11. vue vuex 挂载_【HAVENT原创】Vue 中使用 Vuex 的几种写法
  12. android高德地图自定义定位图标并具有类似陀螺仪旋转功能。
  13. 视频编解码-----理论基础(3)
  14. android 5.0+原生质设计,cardview、Recyclerview、百分比布局PercentRelativeLayout简单使用
  15. Window git 命令设置alias快捷
  16. 计算机要执行一条指令,cpu所涉及的操作应该包括下列的,计算机一级填空选择题与答案.doc...
  17. HTML简单汇总(不全)
  18. SURFRAD (Surface Radiation Budget) Network 数据下载
  19. mysql缓冲和缓存设置
  20. Windows 10 下C盘空间清理全攻略(Win10 C盘清理 )

热门文章

  1. redis实现消息队列的几种方式及其优劣
  2. 笔记-组织级项目管理与大型项目管理-DIPP
  3. CCF 分蛋糕(满分代码 + 解题思路 :模拟)201703-1
  4. Python爬取豆瓣动作电影好评前100名
  5. 方舟服务器网络信息错误,明日方舟网络安全配置初始化失败请重试\n错误号-1解决办法...
  6. java:P1518 [USACO2.4]两只塔姆沃斯牛 The Tamworth Two
  7. Vue ElementUI table通过改css样式实现斜线表头
  8. C# 使用 DictionaryEntry 在WinForm中给 ComboBox 添加 Key 和 Value
  9. 常见经典动效实现总结(老虎机、打字机、纸牌翻转等等)
  10. Vue中对拿到的数据进行A-Z排序