本地大图片的处理

QAQ学Android真的还是要在项目中获得锻炼,脱离实际一切都是耍流氓哼唧~!

花了一下午时间搞定了项目中要实现的:获取本地图片缩略图并显示在ListView上的,并且点击要能获得该图片文件路径功能,下面先上效果图:


作为一个新手,大概碰到这种需求的思路就是:

首先,递归遍历本地所有文件,然后按文件后缀名找出所有的图片文件,更好的方式是在媒体库里查找所有的图片(系统已经帮你过滤好了所有的图片文件直接去调用就阔以了),再通过得到的文件对象file显示图像。

当然这种处理结果就是大概1~2张图片就直接OOM了。(反正我手机里图片都是至少上MB的...)。

所以呢,必须对图片进行压缩,于是我又在网上找到了一个比较好的图片压缩方法(这里没有引用转载地址了,1是因为是昨天找到的现在已经找不到网址了,2是因为很多篇博客都是相同的方法相同的注释,我也不知道到底谁才是原作...):

[java]  view plain  copy
  1. /*    *//** 
  2.      * 根据指定的图像路径和大小来获取缩略图 
  3.      * 此方法有两点好处: 
  4.      *     1. 使用较小的内存空间,第一次获取的bitmap实际上为null,只是为了读取宽度和高度, 
  5.      *        第二次读取的bitmap是根据比例压缩过的图像,第三次读取的bitmap是所要的缩略图。 
  6.      *     2. 缩略图对于原图像来讲没有拉伸,这里使用了2.2版本的新工具ThumbnailUtils,使 
  7.      *        用这个工具生成的图像不会被拉伸。 
  8.      * @param imagePath 图像的路径 
  9.      * @param width 指定输出图像的宽度 
  10.      * @param height 指定输出图像的高度 
  11.      * @return 生成的缩略图 
  12.      *//* 
  13.     private Bitmap getImageThumbnail(String imagePath, int width, int height) { 
  14.         Bitmap bitmap = null; 
  15.         BitmapFactory.Options options = new BitmapFactory.Options(); 
  16.         options.inJustDecodeBounds = true; 
  17.         // 获取这个图片的宽和高,注意此处的bitmap为null 
  18.         bitmap = BitmapFactory.decodeFile(imagePath, options); 
  19.         options.inJustDecodeBounds = false; // 设为 false 
  20.         // 计算缩放比 
  21.         int h = options.outHeight; 
  22.         int w = options.outWidth; 
  23.         int beWidth = w / width; 
  24.         int beHeight = h / height; 
  25.         int be = 1; 
  26.         if (beWidth < beHeight) { 
  27.             be = beWidth; 
  28.         } else { 
  29.             be = beHeight; 
  30.         } 
  31.         if (be <= 0) { 
  32.             be = 1; 
  33.         } 
  34.         options.inSampleSize = be; 
  35.         // 重新读入图片,读取缩放后的bitmap,注意这次要把options.inJustDecodeBounds 设为 false 
  36.         bitmap = BitmapFactory.decodeFile(imagePath, options); 
  37.         // 利用ThumbnailUtils来创建缩略图,这里要指定要缩放哪个Bitmap对象 
  38.         bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, 
  39.                 ThumbnailUtils.OPTIONS_RECYCLE_INPUT); 
  40.         return bitmap; 
  41.     }*/  
方法很简单,然而可以发现这个方法其实是做了这么几件事情:

1、根据传入的图片路径构造bitmap,得到原图的宽高.

2、计算图片合适的缩放比.

3、利用ThumbnailUtils来创建缩略图,然后返回这个最终缩放以后的bitmap.

尽管像方法中说的那样:使用较小的内存空间,第一次获取的bitmap实际上为null,只是为了读取宽度和高度, 第二次读取的bitmap是根据比例压缩过的图像,第三次读取的bitmap是所要的缩略图。

然而整个方法还是开辟了3个bitmap对象的内存区域,这还不考虑ThumbnailUtils.extractThumbnail()方法所耗费的时空间。

所以当我使用了这个方法实现了在ListView中遍历本地图片的时候,上下滑起来是灰常卡滴(这里就不贴gif图了有兴趣想知道的朋友可以自己尝试一下)


Finaly,在踏破铁鞋无觅处之后,终于找到了最终解决方法,也是一开始忽略的方法:

原来一直不知道的Thumbnails类,才是解决问题的关键。

在Android系统中也有对应的thumbnails文件,下面是百度百科对它的描述:


然后在MediaStore媒体库类中,也是有Thumbnails这么一个内部类的:

[java]  view plain  copy
  1. /** 
  2.         * This class allows developers to query and get two kinds of thumbnails: 
  3.         * MINI_KIND: 512 x 384 thumbnail 
  4.         * MICRO_KIND: 96 x 96 thumbnail 
  5.         */  
  6.        public static class Thumbnails implements BaseColumns {  
  7.            public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {  
  8.                return cr.query(uri, projection, nullnull, DEFAULT_SORT_ORDER);  
  9.            }  
  10.   
  11.            public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,  
  12.                    String[] projection) {  
  13.                return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);  
  14.            }  
  15.   
  16.            public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,  
  17.                    String[] projection) {  
  18.                return cr.query(EXTERNAL_CONTENT_URI, projection,  
  19.                        IMAGE_ID + " = " + origId + " AND " + KIND + " = " +  
  20.                        kind, nullnull);  
  21.            }  
  22.   
  23.            /** 
  24.             * This method cancels the thumbnail request so clients waiting for getThumbnail will be 
  25.             * interrupted and return immediately. Only the original process which made the getThumbnail 
  26.             * requests can cancel their own requests. 
  27.             * 
  28.             * @param cr ContentResolver 
  29.             * @param origId original image id 
  30.             */  
  31.            public static void cancelThumbnailRequest(ContentResolver cr, long origId) {  
  32.                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,  
  33.                        InternalThumbnails.DEFAULT_GROUP_ID);  
  34.            }  
  35.   
  36.            /** 
  37.             * This method checks if the thumbnails of the specified image (origId) has been created. 
  38.             * It will be blocked until the thumbnails are generated. 
  39.             * 
  40.             * @param cr ContentResolver used to dispatch queries to MediaProvider. 
  41.             * @param origId Original image id associated with thumbnail of interest. 
  42.             * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND. 
  43.             * @param options this is only used for MINI_KIND when decoding the Bitmap 
  44.             * @return A Bitmap instance. It could be null if the original image 
  45.             *         associated with origId doesn't exist or memory is not enough. 
  46.             */  
  47.            public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,  
  48.                    BitmapFactory.Options options) {  
  49.                return InternalThumbnails.getThumbnail(cr, origId,  
  50.                        InternalThumbnails.DEFAULT_GROUP_ID, kind, options,  
  51.                        EXTERNAL_CONTENT_URI, false);  
  52.            }  
  53.   
  54.            /** 
  55.             * This method cancels the thumbnail request so clients waiting for getThumbnail will be 
  56.             * interrupted and return immediately. Only the original process which made the getThumbnail 
  57.             * requests can cancel their own requests. 
  58.             * 
  59.             * @param cr ContentResolver 
  60.             * @param origId original image id 
  61.             * @param groupId the same groupId used in getThumbnail. 
  62.             */  
  63.            public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {  
  64.                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);  
  65.            }  
  66.   
  67.            /** 
  68.             * This method checks if the thumbnails of the specified image (origId) has been created. 
  69.             * It will be blocked until the thumbnails are generated. 
  70.             * 
  71.             * @param cr ContentResolver used to dispatch queries to MediaProvider. 
  72.             * @param origId Original image id associated with thumbnail of interest. 
  73.             * @param groupId the id of group to which this request belongs 
  74.             * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND. 
  75.             * @param options this is only used for MINI_KIND when decoding the Bitmap 
  76.             * @return A Bitmap instance. It could be null if the original image 
  77.             *         associated with origId doesn't exist or memory is not enough. 
  78.             */  
  79.            public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,  
  80.                    int kind, BitmapFactory.Options options) {  
  81.                return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,  
  82.                        EXTERNAL_CONTENT_URI, false);  
  83.            }  
  84.   
  85.            /** 
  86.             * Get the content:// style URI for the image media table on the 
  87.             * given volume. 
  88.             * 
  89.             * @param volumeName the name of the volume to get the URI for 
  90.             * @return the URI to the image media table on the given volume 
  91.             */  
  92.            public static Uri getContentUri(String volumeName) {  
  93.                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +  
  94.                        "/images/thumbnails");  
  95.            }  
  96.   
  97.            /** 
  98.             * The content:// style URI for the internal storage. 
  99.             */  
  100.            public static final Uri INTERNAL_CONTENT_URI =  
  101.                    getContentUri("internal");  
  102.   
  103.            /** 
  104.             * The content:// style URI for the "primary" external storage 
  105.             * volume. 
  106.             */  
  107.            public static final Uri EXTERNAL_CONTENT_URI =  
  108.                    getContentUri("external");  
  109.   
  110.            /** 
  111.             * The default sort order for this table 
  112.             */  
  113.            public static final String DEFAULT_SORT_ORDER = "image_id ASC";  
  114.   
  115.            /** 
  116.             * The data stream for the thumbnail 
  117.             * <P>Type: DATA STREAM</P> 
  118.             */  
  119.            public static final String DATA = "_data";  
  120.   
  121.            /** 
  122.             * The original image for the thumbnal 
  123.             * <P>Type: INTEGER (ID from Images table)</P> 
  124.             */  
  125.            public static final String IMAGE_ID = "image_id";  
  126.   
  127.            /** 
  128.             * The kind of the thumbnail 
  129.             * <P>Type: INTEGER (One of the values below)</P> 
  130.             */  
  131.            public static final String KIND = "kind";  
  132.   
  133.            public static final int MINI_KIND = 1;  
  134.            public static final int FULL_SCREEN_KIND = 2;  
  135.            public static final int MICRO_KIND = 3;  
  136.            /** 
  137.             * The blob raw data of thumbnail 
  138.             * <P>Type: DATA STREAM</P> 
  139.             */  
  140.            public static final String THUMB_DATA = "thumb_data";  
  141.   
  142.            /** 
  143.             * The width of the thumbnal 
  144.             * <P>Type: INTEGER (long)</P> 
  145.             */  
  146.            public static final String WIDTH = "width";  
  147.   
  148.            /** 
  149.             * The height of the thumbnail 
  150.             * <P>Type: INTEGER (long)</P> 
  151.             */  
  152.            public static final String HEIGHT = "height";  
  153.        }  
  154.    }  
我们可以从中找到几个可用于Cursor查找的重要参数:

/**
 * The data stream for the thumbnail
 * <P>Type: DATA STREAM</P>
 */
public static final String DATA = "_data";

/**
 * The original image for the thumbnal
 * <P>Type: INTEGER (ID from Images table)</P>
 */
public static final String IMAGE_ID = "image_id";
/**
 * The content:// style URI for the "primary" external storage
 * volume.
 */
public static final Uri EXTERNAL_CONTENT_URI =
        getContentUri("external");
有了这三个参数,我们就可以很轻松从本地媒体库中获得图片缩略图的ID和路径。

[java]  view plain  copy
  1. //先得到缩略图的URL和对应的图片id  
  2. Cursor cursor = cr.query(  
  3.         Thumbnails.EXTERNAL_CONTENT_URI,  
  4.         new String[]{  
  5.                 Thumbnails.IMAGE_ID,  
  6.                 Thumbnails.DATA  
  7.         },  
  8.         null,  
  9.         null,  
  10.         null);  

这里的缩略图ID有什么用呢?我们从它的注释中可以很明显地得到:

      /**
             * The original image for the thumbnal
             * <P>Type: INTEGER (ID from Images table)</P>

ID from Images table!!!这个ID是跟多媒体库中的images表的ID相对应的,由此,我们可以通过这个id来设置cursor的查找条件,从而找出images表中对应的真正的图片文件的路径!

从而完美地实现了文章开头的功能需求。

下面是完整的代码:

获得一个HashMap参数的ArrayList,HashMap项的键"thumbnail_path"对应真实图片路径值,键"image_id_path"对应缩略图路径值,有了这两个路径,想干嘛干嘛了2333

[java]  view plain  copy
  1. /** 
  2.      * 得到本地图片文件 
  3.      * @param context 
  4.      * @return 
  5.      */  
  6.     public static ArrayList<HashMap<String,String>> getAllPictures(Context context) {  
  7.         ArrayList<HashMap<String,String>> picturemaps = new ArrayList<>();  
  8.         HashMap<String,String> picturemap;  
  9.         ContentResolver cr = context.getContentResolver();  
  10.         //先得到缩略图的URL和对应的图片id  
  11.         Cursor cursor = cr.query(  
  12.                 Thumbnails.EXTERNAL_CONTENT_URI,  
  13.                 new String[]{  
  14.                         Thumbnails.IMAGE_ID,  
  15.                         Thumbnails.DATA  
  16.                 },  
  17.                 null,  
  18.                 null,  
  19.                 null);  
  20.         if (cursor.moveToFirst()) {  
  21.             do {  
  22.                 picturemap = new HashMap<>();  
  23.                 picturemap.put("image_id_path",cursor.getInt(0)+"");  
  24.                 picturemap.put("thumbnail_path",cursor.getString(1));  
  25.                 picturemaps.add(picturemap);  
  26.             } while (cursor.moveToNext());  
  27.             cursor.close();  
  28.         }  
  29.         //再得到正常图片的path  
  30.         for (int i = 0;i<picturemaps.size();i++) {  
  31.             picturemap = picturemaps.get(i);  
  32.             String media_id = picturemap.get("image_id_path");  
  33.             cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,  
  34.                     new String[]{  
  35.                             MediaStore.Images.Media.DATA  
  36.                     },  
  37.                     MediaStore.Audio.Media._ID+"="+media_id,  
  38.                     null,  
  39.                     null  
  40.             );  
  41.             if (cursor.moveToFirst()) {  
  42.                 do {  
  43.                     picturemap.put("image_id",cursor.getString(0));  
  44.                     picturemaps.set(i,picturemap);  
  45.                 } while (cursor.moveToNext());  
  46.                 cursor.close();  
  47.             }  
  48.         }  
  49.         return picturemaps;  
  50.     }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值