系统相册分析(GallerPicker)

系统相册会调用android的隐藏api。因此,直接编译会报错。需要导入系统包:framework_intermediates/classes.jar (android的框架类)  网上一搜就能搜到。把包作为user liblary引用到项目中来,在解决一些版本兼容问题,就可以编译了。不过上面我编译的代码,把调用系统隐藏api的地方改成了替代代码,其他兼容错误也解决了,可以直接编译,运行起来可能会有问题。可以根据相应问题来解决。

1.获取数据

    a.文件夹列表

    相册的数据当然是媒体数据,包括图片和视频。相册的文件夹列表除了实际的图片文件夹分类,相册还添加了相机图片、相机视频、所有图片、所有视频几个分类。

    这些分类数据也以图片文件夹的形式列出来。文件夹列表的数据是怎么获取的呢,当然,可以自己到sdcard中去找,当然这就2了。系统将这个工作已经做了,系统会维护一个Media数据库来存储这些媒体数据信息。以前自己也使用过Media数据库来查找媒体数据信息,看了相册使用Media数据库,瞬间感觉自己的方式弱爆了。

    相册的列表页面是GalleryPicker,当加载列表数据的时候会执行下面这个方法:

  1. private void workerRun() {
  2. ArrayList<Item> allItems = new ArrayList<Item>();

  3. checkScanning();//检查系统Media库扫描后台是否还在执行
  4. .....

  5. checkImageList(allItems);//获取系统媒体数据列表,这里就包括所有的图片文件夹列表、相机图片、相机视频、所有图片、所有视频
  6. .....

  7. checkBucketIds(allItems);//下面是获取sdcard文件夹列表数据 ps:个人觉得这个方法和上面的checkImageList方法的名字很有歧义啊。根据方法名很容易理解为checkImageList是先获取整个列表,checkBucketIds方法是获取列表需要的数据。被名字忽悠了。应该叫做checkInternalList 和 checkExternalList嘛。

  8. checkThumbBitmap(allItems);

  9. checkLowStorage();
  10. }
复制代码

    下面是获取系统媒体列表数据,列表有5类,包括相机图片、相机视频、相机媒体(相机图片+相机视频)、所有图片、所有视频

  1. private void checkImageList(ArrayList<Item> allItems) {
  2. int length = IMAGE_LIST_DATA.length;//5类列表的数据全部定义在IMAGE_LIST_DATA里面
  3. IImageList[] lists = new IImageList[length];
  4. for (int i = 0; i < length; i++) {
  5. ImageListData data = IMAGE_LIST_DATA[i];
  6. lists[i] = createImageList(data.mInclude, data.mBucketId,
  7. getContentResolver());
  8. .....
  9. Item item = new Item(data.mType, data.mBucketId, getResources()
  10. .getString(data.mStringId), lists[i]);

  11. allItems.add(item);

  12. final Item finalItem = item;
  13. mHandler.post(new Runnable() {
  14. public void run() {
  15. updateItem(finalItem);
  16. }
  17. });
  18. }
  19. }
复制代码

    里面抽象定义的数据比较多,这里介绍不可能太清楚。可以取看看代码,仔细研究一下。总体说来,这里得到相机图片、相机视频、相机媒体(相机图片+相机视频)、所有图片、所有视频这几种数据的列表。列表的结构是ImageList、VideoList等,它们都是BaseImageList的子类,代码在com.android.camera.gallery包下面。

    下面是获取sdcard文件夹列表数据


  1. private void checkBucketIds(ArrayList<Item> allItems) {
  2. final IImageList allImages;
  3. //获取所有数据列表
  4. if (!mScanning && !mUnmounted) {
  5. allImages = ImageManager.makeImageList(getContentResolver(),
  6. ImageManager.DataLocation.ALL, ImageManager.INCLUDE_IMAGES
  7. | ImageManager.INCLUDE_VIDEOS,
  8. ImageManager.SORT_DESCENDING, null);
  9. } else {
  10. allImages = ImageManager.makeEmptyImageList();
  11. }
  12. .....

  13. //这个地方这句话,是比较屌的,直接就查到了sdcard中的文件夹列表。以前,自己写这一块。就很2地取Media数据库,把所有的图片文件路径读出来,在来截取生成列表。相册是不是这样写的,具体,下面会介绍
  14. HashMap<String, String> hashMap = allImages.getBucketIds();
  15. allImages.close();

  16. for (Map.Entry<String, String> entry : hashMap.entrySet()) {
  17. String key = entry.getKey();
  18. if (!key.equals(CAMERA_BUCKET)) {
  19. IImageList list = createImageList(ImageManager.INCLUDE_IMAGES
  20. | ImageManager.INCLUDE_VIDEOS, key,
  21. getContentResolver());
  22. .....
  23. Item item = new Item(Item.TYPE_NORMAL_FOLDERS, key,
  24. entry.getValue(), list);

  25. allItems.add(item);

  26. final Item finalItem = item;
  27. mHandler.post(new Runnable() {
  28. public void run() {
  29. updateItem(finalItem);
  30. }
  31. });
  32. }
  33. }

  34. mHandler.post(new Runnable() {
  35. public void run() {
  36. checkBucketIdsFinished();
  37. }
  38. });
  39. }
复制代码

    上面的全部都是招式,下面才是内功,也就是获取列表的核心部分,由于相册把这一块做了很多抽象,因此,我把核心的代码整理出来

  1. package com.example.demo;

  2. import java.util.HashMap;

  3. import android.content.ContentResolver;
  4. import android.database.Cursor;
  5. import android.net.Uri;
  6. import android.os.Environment;
  7. import android.provider.MediaStore.Images;
  8. import android.provider.MediaStore.Images.Media;

  9. /**
  10. * 获取系统Midia数据库数据,Midia数据库要这么用
  11. *
  12. * @author johnnyxyz
  13. * @mail johnnyxyzw@gmail.com
  14. */
  15. public class MediaListGetter {
  16. public static final Uri EXTERNAL_STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI;
  17. public static final Uri INTERNAL_STORAGE_URI = Images.Media.INTERNAL_CONTENT_URI;
  18. public static final Uri VIDEO_STORAGE_URI = Uri.parse("content://media/external/video/media");

  19. private static final String[] ACCEPTABLE_IMAGE_TYPES = new String[] { "image/jpeg",
  20. "image/png", "image/gif" };

  21. private static final String WHERE_CLAUSE = "(" + Media.MIME_TYPE + " in (?, ?, ?))";
  22. private static final String WHERE_CLAUSE_WITH_BUCKET_ID = WHERE_CLAUSE + " AND "
  23. + Media.BUCKET_ID + " = ?";

  24. protected String whereClause(String bucketId) {
  25. return bucketId == null ? WHERE_CLAUSE : WHERE_CLAUSE_WITH_BUCKET_ID;
  26. }

  27. private String[] whereClauseArgs(String bucketId) {
  28. if (bucketId != null) {
  29. int count = ACCEPTABLE_IMAGE_TYPES.length;
  30. String[] result = new String[count + 1];
  31. System.arraycopy(ACCEPTABLE_IMAGE_TYPES, 0, result, 0, count);
  32. result[count] = bucketId;
  33. return result;
  34. }
  35. return ACCEPTABLE_IMAGE_TYPES;
  36. }

  37. public static final String CAMERA_IMAGE_BUCKET_NAME = Environment.getExternalStorageDirectory()
  38. .toString() + "/DCIM/Camera";
  39. public static final String CAMERA_IMAGE_BUCKET_ID = String.valueOf(CAMERA_IMAGE_BUCKET_NAME
  40. .toLowerCase().hashCode());

  41. public MediaListGetter(ContentResolver mContentResolver) {
  42. super();
  43. this.mContentResolver = mContentResolver;
  44. }

  45. private final ContentResolver mContentResolver;

  46. /**
  47. * 获取所有Camera图片文件夾列表
  48. * @return
  49. */
  50. public HashMap<String, String> getCameraImages() {
  51. // 内置存储的图片
  52. Uri baseUri = INTERNAL_STORAGE_URI;
  53. Uri uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  54. Cursor internal = Media.query(mContentResolver, uri, new String[] {
  55. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, whereClause(CAMERA_IMAGE_BUCKET_ID),
  56. whereClauseArgs(CAMERA_IMAGE_BUCKET_ID), null);

  57. // 外置存储的图片
  58. baseUri = EXTERNAL_STORAGE_URI;
  59. uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  60. Cursor external = Media.query(mContentResolver, uri, new String[] {
  61. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, whereClause(CAMERA_IMAGE_BUCKET_ID),
  62. whereClauseArgs(CAMERA_IMAGE_BUCKET_ID), null);

  63. try {
  64. HashMap<String, String> hash = new HashMap<String, String>();
  65. while (internal.moveToNext()) {
  66. hash.put(internal.getString(1), internal.getString(0));
  67. }
  68. while (external.moveToNext()) {
  69. hash.put(external.getString(1), external.getString(0));
  70. }
  71. return hash;
  72. } finally {
  73. internal.close();
  74. external.close();
  75. }
  76. }

  77. /**
  78. * 获取所有Camera视频文件夾列表
  79. * @return
  80. */
  81. public HashMap<String, String> getCameraVidios() {
  82. Uri baseUri = VIDEO_STORAGE_URI;
  83. Uri uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  84. Cursor cursor = Media.query(mContentResolver, uri, new String[] {
  85. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID },
  86. (CAMERA_IMAGE_BUCKET_ID != null ? Images.Media.BUCKET_ID + " = '"
  87. + CAMERA_IMAGE_BUCKET_ID + "'" : null), null, null);

  88. try {
  89. HashMap<String, String> hash = new HashMap<String, String>();
  90. while (cursor.moveToNext()) {
  91. hash.put(cursor.getString(1), cursor.getString(0));
  92. }
  93. return hash;
  94. } finally {
  95. cursor.close();
  96. }
  97. };

  98. /**
  99. * 获取所有Camera媒体文件夾列表
  100. * @return
  101. */
  102. public void getCameraMedias() {
  103. // getCameraVidios + getCameraImages
  104. };

  105. /**
  106. * 获取所有圖片的文件夾列表
  107. * @return
  108. */
  109. public HashMap<String, String> getAllImages() {
  110. Uri baseUri = EXTERNAL_STORAGE_URI;
  111. Uri uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  112. // 外置存储camera图片
  113. Cursor camera = Media.query(mContentResolver, uri, new String[] {
  114. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, whereClause(CAMERA_IMAGE_BUCKET_ID),
  115. whereClauseArgs(CAMERA_IMAGE_BUCKET_ID), null);
  116. // 外置存储非camera图片
  117. Cursor external = Media.query(mContentResolver, uri, new String[] {
  118. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, whereClause(null),
  119. whereClauseArgs(null), null);
  120. // 内置图片
  121. baseUri = INTERNAL_STORAGE_URI;
  122. uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  123. Cursor internal = Media.query(mContentResolver, uri, new String[] {
  124. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, whereClause(null),
  125. whereClauseArgs(null), null);

  126. try {
  127. HashMap<String, String> hash = new HashMap<String, String>();
  128. while (camera.moveToNext()) {
  129. hash.put(camera.getString(1), camera.getString(0));
  130. }
  131. while (external.moveToNext()) {
  132. hash.put(external.getString(1), external.getString(0));
  133. }
  134. while (internal.moveToNext()) {
  135. hash.put(internal.getString(1), internal.getString(0));
  136. }
  137. return hash;
  138. } finally {
  139. camera.close();
  140. external.close();
  141. internal.close();
  142. }
  143. };

  144. /**
  145. * 获取所有視頻的文件夾列表
  146. * @return
  147. */
  148. public HashMap<String, String> getAllVidios() {
  149. Uri baseUri = VIDEO_STORAGE_URI;
  150. Uri uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  151. Cursor cursor = Media.query(mContentResolver, uri, new String[] {
  152. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, null, null, null);
  153. try {
  154. HashMap<String, String> hash = new HashMap<String, String>();
  155. while (cursor.moveToNext()) {
  156. hash.put(cursor.getString(1), cursor.getString(0));
  157. }
  158. return hash;
  159. } finally {
  160. cursor.close();
  161. }
  162. };

  163. /**
  164. * 获取外置存储的所有文件夹
  165. * @return
  166. */
  167. public HashMap<String, String> getExternalFolders() {
  168. Uri baseUri = EXTERNAL_STORAGE_URI;
  169. Uri uri = baseUri.buildUpon().appendQueryParameter("distinct", "true").build();
  170. Cursor cursor = Media.query(mContentResolver, uri, new String[] {
  171. Media.BUCKET_DISPLAY_NAME, Media.BUCKET_ID }, null, null, null);
  172. try {
  173. HashMap<String, String> hash = new HashMap<String, String>();
  174. while (cursor.moveToNext()) {
  175. if (CAMERA_IMAGE_BUCKET_ID.equals(cursor.getString(1)))
  176. continue;
  177. hash.put(cursor.getString(1), cursor.getString(0));
  178. }
  179. return hash;
  180. } finally {
  181. cursor.close();
  182. }
  183. }
  184. }
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值