摘要:本文講解了在 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類)