android仿最新6.2版本微信相册


原文:http://www.2cto.com/kf/201506/410285.html:


仿微信相册选择图片,查看大图,写的不太好,希望评论指出不足,谅解,先介绍一下我的基本思路

第一步获取手机上的所有图片路径:

 

?
1
2
3
4
5
6
7
8
9
10
11
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver contentResolver = getContentResolver();
//获取jpeg和png格式的文件,并且按照时间进行倒序
Cursor cursor = contentResolver.query(uri, null , MediaStore.Images.Media.MIME_TYPE + "=\"image/jpeg\" or " +
         MediaStore.Images.Media.MIME_TYPE + "=\"image/png\"" , null , MediaStore.Images.Media.DATE_MODIFIED+ " desc" );
if (cursor != null ){
     while (cursor.moveToNext()){
         //do something
     }
     handler.sendEmptyMessage( 0 );
}

 

我的存储格式

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/** 按时间排序的所有图片list */
private ArrayList<singleimagemodel> allImages;
/** 按目录排序的所有图片list */
private ArrayList<singleimagedirectories> imageDirectories;
  /**
  * 一个文件夹中的图片数据实体
  */
private class SingleImageDirectories{
     /** 父目录的路径 */
     public String directoryPath;
     /** 目录下的所有图片实体 */
     public ImageDirectoryModel images;
}</singleimagedirectories></singleimagemodel>

一个是全部图片的存储顺序,第二个是按照目录的图片存储顺序

 

第二步,获取到图片之后,放入到gridview中进行显示,但是BitmapFactory.decodeFile()函数会非常耗时,所以为了使得非常流畅的显示图片,创建一个类AlbumBitmapCacheHelper.class,用来异步加载图片,

该类使用LruCache cache来缓存Bitmap,使得存储图片不会造成oom,我这里设置cache的初始大小为1/4的运行时内存

然后使用ThreadPoolExecutor线程池来处理图片的显示,线程池大小应该设置适中

做完这两件事情之后就可以用来加载图片了,方法getBitmap用来讲

?
1
2
3
4
5
6
7
Bitmap bitmap = getBitmapFromCache(path, width, height);
//如果能够从缓存中获取符合要求的图片,则直接回调
if (bitmap != null ) {
} else {
     //新建线程放入线程池去处理该图片的显示
}
return bitmap;

如果cache中找不到该图片,则调用BitmapFactory.decodeFile()去加载图片,加载图片不能够直接加载原图,会造成OOM,所以要去处理压缩比

 

?
1
2
3
4
5
6
7
8
9
10
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true ;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = computeScale(options, width, height);
options.inJustDecodeBounds = false ;
bitmap = BitmapFactory.decodeFile(path, options);
//获取之后,放入缓存,以便下次继续使用
if (bitmap != null && cache!= null ) {
     cache.put(path, bitmap);
}

方法computeScale()主要是计算图片最小的压缩比,

 

?
1
 
?
1
这样在gridview中的getview方法中去调用AlbumBitmapCacheHelper. class 的getBitmap方法即可, 但是这样会有很多的问题:
?
1
2
3
一个问题就是图片显示会闪,这主要是由于getview的view的复用,解决方法就是使用settag方法
holder.iv_content.setTag(path);
将要显示的Imageview的tag设置为需要显示的图片路径,这样在回调的时候使用方法gridView.findViewWithTag(path),找到这个imageview进行显示,闪的问题就解决了
?
1
 
?
1
第二个问题就是加载速度很慢,拉的速度很快的情况下,图片要很久才会加载出来,特别是很大的图片,比如拍照和截图的照片,
?
1
解决方法第一方案就是在AlbumBitmapCacheHelper类中维护一个ArrayList<string> currentShowString,在getview方法中,如果该图片要显示,则直接将path加入到该list中,同时如果这个view的tag不为空,说明该view的原来的path是不需要显示的,所以需要将这个path从list中删除:</string>
?
1
 
?
1
//优化显示效果 if(holder.iv_content.getTag() != null) { String remove = (String) holder.iv_content.getTag(); AlbumBitmapCacheHelper.getInstance().removePathFromShowlist(remove); } AlbumBitmapCacheHelper.getInstance().addPathToShowlist(path);
这样在线程池中的处理方式就是先查看需要显示的path是否在list中,如果没有在list中,则该线程直接关闭,如果在list中,则显示该图片
?
1
 
?
1
if (!currentShowString.contains(path)||cache== null ) { return ; }


?
1
第二个方案就是如果显示的图片很大,特别是拍照,截图和解图的图片,decode有时会耗时几秒中,微信显示效果非常好,我自己想出来的处理的方式就是
?
1
2
3
***第一步,从应用的缓存temp目录下取,如果取不到,
***第二步,计算图片的压缩比例samplesize,如果samplesize < 4 ,图片的BitmapFactory.decodeFile()时间短,直接返回图片,但是如果 samplesize > 4 ,执行第三步
***第三步则将压缩后的图片存入temp目录下,以便下次快速取出这样显示图片的效果就出来了,显示的速度除了和微信一样第一次大图加载慢之外,之后的显示就能很快了,
?
1
 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if (! new File(CommonUtil.getDataPath()).exists())
     new File(CommonUtil.getDataPath()).mkdirs();
//临时文件的文件名
String tempPath = CommonUtil.getDataPath() + hash + ".temp" ;
//如果该文件存在
if ( new File(tempPath).exists())
     bitmap = BitmapFactory.decodeFile(tempPath);
......
//第三步,如果缩放比例大于4,该图的加载会非常慢,所以将该图保存到临时目录下以便下次的快速加载
     if (options.inSampleSize >= 4 ) {
         try {
             File file = new File(tempPath);
             if (!file.exists())
                 file.createNewFile();
             FileOutputStream fos = new FileOutputStream(file);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 100 , baos);
             fos.write(baos.toByteArray());
             fos.flush();
             fos.close();
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }

问题就差不多解决了

第三步大图的查看,大图只要是使用的网上找的ZoomImageView+viewpagger的组合,但是使用这个出现的问题就是很容易OOM,没办法,我的处理方式就是在点进去大图的时候

 

 

?
1
2
3
public void releaseHalfSizeCache() {
     cache.resize(( int ) (Runtime.getRuntime().maxMemory() / 1024 / 8 ));
}

直接将cache的大小变成原来的一半,因为查看大图页,加载一张大图占用的内存就很大,这样显示效果页还凑合,有别的方法,一定要留言告诉我

注意:大图的查看由于需要通过intent传递数据,但是intent传递的数据大小不能太大,如果手机上有几千张图片,则数据量大小可能会超过intent所能传递的最大量,所以可以写入一个公共的地方,内存,数据库,文件都可以,

?
1
2
//TODO 这里由于涉及到intent传递的数据不能太大的问题,所以如果需要,这里要进行另外的处理,写入到内存或者写入到文件中 
intent.putExtra(PickBigImagesActivity.EXTRA_DATA, getAllImagesFromCurrentDirectory());

我暂时没有处理~~

 

第四步就是图片选择完成之后,完成善后工作,将AlbumBitmapCacheHelper类中cache清空,差不多就这样了,还有很多的小问题,比如图片时间的显示,具体大家看源码

 


\ \

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值