摘要:本文讲解了在 Android Studio 中如何通过 List Fragments 创建一个以缩略图整列展示设备中图片的相册应用。
这是关于在Android Studio中通过 fragments 进行相机方面开发的五篇系列文章的第二篇。如果你还没有把我放在 GitHub 上的范例程序克隆下来,那么请先去这里获取最新代码。本文主要包含的是 “SimplePhotoGalleryListFragment” 这个 Fragment。
注意:本范例中所涉及的 List Fragment 的用法,可以在 list fragments 这篇文章中找到详细的讲解。
AsyncTaskLoaders 以及 Fragments
加载整个图片库到List是一个运算量比较密集,强度很高任务。因此,我们希望利用 Android 提供的AsyncTaskLoader 通过异步加载解决这个问题。在这里,我已经写好了一个自定义AsyncTaskLoader工具类用加载图库中图片的。我把它命名为:PhotoGalleryImageProvider,可以在源码中找到。
Fragments 提供了一种特殊的接口给异步任务的 Loader 以便于自动触发异步加载任务。我们的图库列表在Fragment中看起来如下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
; html-script: false ] @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create an empty loader and pre-initialize the photo list items as an empty list. Context context = getActivity().getBaseContext(); // Set up empty mAdapter mPhotoListItem = new ArrayList() ; mAdapter = new PhotoAdapter(context, R.layout.photo_item, mPhotoListItem, false); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } |
请注意最后的这一行:
1 2 |
; html-script: false ] getLoaderManager().initLoader(0, null, this); |
这一行的作用就是自动启用 AsyncLoader。AsyncLoader的相关代码放在这个Class文件的后面。
1 2 3 4 5 6 7 8 9 10 11 |
; html-script: false ] /** * Loader Handlers for loading the photos in the background. */ @Override public Loader<List> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader with no arguments, so it is simple. return new PhotoGalleryAsyncLoader(getActivity()); } |
每次后台任务成功获取到图库中的图片时,则会回调下面这个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
; html-script: false ] @Override public void onLoadFinished(Loader<List> loader, List data) { // Set the new data in the mAdapter. mPhotoListItem.clear(); for(int i = 0; i < data.size();i++){ PhotoItem item = data.get(i); mPhotoListItem.add(item); } mAdapter.notifyDataSetChanged(); resolveEmptyText(); cancelProgressDialog(); } |
其中,PhotoItem(用作给 Adapter 存储数据)的数组包含了指向所有图库中图片的缩略图以及全尺寸图片的URL。一旦获取这些数据,Adapter必定会通过 “notifyDataSetChanged” 回调来通知出去,从而刷新当前的图片列表。
通过游标(cursor)来获取缩略图
之前我提到过,我已经提供了一个工具类可以用游标方便的去获取图库中图片的缩略图,这个工具类叫做“PhotoGalleryImageProvider”。这个类的主要用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
; html-script: false ] /** * Fetch both full sized images and thumbnails via a single query. * Returns all images not in the Camera Roll. * @param context * @return */ public static List getAlbumThumbnails(Context context){ final String[] projection = {MediaStore.Images.Thumbnails.DATA,MediaStore.Images.Thumbnails.IMAGE_ID}; Cursor thumbnailsCursor = context.getContentResolver().query( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, projection, // Which columns to return null, // Return all rows null, null); ... return result; } |
直接用Android 提供的Cursors 去后台获取图片是比较简单的一种用法。另一种高级的用法则是使用 CursorLoader 来操作Cursor。CursorLoader 内建了一个 AsyncTaskLoader 可以用来自动处理后台的加载进程。由于需要同时渲染获取到图片的缩略图和完整尺寸的图片,所以尽管使用带有CursorLoader的AsyncTask也可以得到同样的结果,但我还是选择了写一个自定义的Task Loader。
除了这些必须了解的内容,你现在可以获取范例代码然后好好享受学习的旅程了!
相关连接
- List all camera images (用作分部创建cursor loader类)