本文主要是介绍Android进阶 -- 知乎Matisse源码解析(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本篇博客一起来看Matisse的数据加载机制。
一、AlbumLoader
Matisse采用Loader机制进行加载,先来看AlbumLoader。AlbumLoader集成自CursorLoader,作为资源加载器,加载好资源之后,通过AlbumCollection实现的LoaderManager.LoaderCallbacks接口,将包含数据的Cursor回调给外部调用的MatissActivity。
Loader机制是一种异步加载数据的方式,同常常使用的Handler + Thread方式或者AsyncTask方式一样,被用作数据的异步加载。
相比较于Handler + Thread或者AsyncTask来讲,Loader的封装程度更高,使用起来更简洁,但是灵活性上相比前两者就显得不够灵活。
下面这段代码,通过定义不同的约束,返回了AlbumAdapter实例,Java多态的体现。
public static CursorLoader newInstance(Context context) {String selection;String[] selectionArgs;if (SelectionSpec.getInstance().onlyShowGif()) {selection = beforeAndroidTen()? SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE : SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE_29;selectionArgs = getSelectionArgsForSingleMediaGifType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE);} else if (SelectionSpec.getInstance().onlyShowImages()) {selection = beforeAndroidTen()? SELECTION_FOR_SINGLE_MEDIA_TYPE : SELECTION_FOR_SINGLE_MEDIA_TYPE_29;selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE);} else if (SelectionSpec.getInstance().onlyShowVideos()) {selection = beforeAndroidTen()? SELECTION_FOR_SINGLE_MEDIA_TYPE : SELECTION_FOR_SINGLE_MEDIA_TYPE_29;selectionArgs = getSelectionArgsForSingleMediaType(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO);} else {selection = beforeAndroidTen() ? SELECTION : SELECTION_29;selectionArgs = SELECTION_ARGS;}return new AlbumLoader(context, selection, selectionArgs);}
然后在loadInBackgroud方法中,进行数据的查询
@Overridepublic Cursor loadInBackground() {Cursor albums = super.loadInBackground();MatrixCursor allAlbum = new MatrixCursor(COLUMNS);if (beforeAndroidTen()) {int totalCount = 0;Uri allAlbumCoverUri = null;MatrixCursor otherAlbums = new MatrixCursor(COLUMNS);if (albums != null) {while (albums.moveToNext()) {long fileId = albums.getLong(albums.getColumnIndex(MediaStore.Files.FileColumns._ID));long bucketId = albums.getLong(albums.getColumnIndex(COLUMN_BUCKET_ID));String bucketDisplayName = albums.getString(albums.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME));String mimeType = albums.getString(albums.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE));Uri uri = getUri(albums);int count = albums.getInt(albums.getColumnIndex(COLUMN_COUNT));otherAlbums.addRow(new String[]{Long.toString(fileId),Long.toString(bucketId), bucketDisplayName, mimeType, uri.toString(),String.valueOf(count)});totalCount += count;}if (albums.moveToFirst()) {allAlbumCoverUri = getUri(albums);}}allAlbum.addRow(new String[]{Album.ALBUM_ID_ALL, Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null,allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(),String.valueOf(totalCount)});return new MergeCursor(new Cursor[]{allAlbum, otherAlbums});} else {int totalCount = 0;Uri allAlbumCoverUri = null;// Pseudo GROUP BYMap<Long, Long> countMap = new HashMap<>();if (albums != null) {while (albums.moveToNext()) {long bucketId = albums.getLong(albums.getColumnIndex(COLUMN_BUCKET_ID));Long count = countMap.get(bucketId);if (count == null) {count = 1L;} else {count++;}countMap.put(bucketId, count);}}MatrixCursor otherAlbums = new MatrixCursor(COLUMNS);if (albums != null) {if (albums.moveToFirst()) {allAlbumCoverUri = getUri(albums);Set<Long> done = new HashSet<>();do {long bucketId = albums.getLong(albums.getColumnIndex(COLUMN_BUCKET_ID));if (done.contains(bucketId)) {continue;}long fileId = albums.getLong(albums.getColumnIndex(MediaStore.Files.FileColumns._ID));String bucketDisplayName = albums.getString(albums.getColumnIndex(COLUMN_BUCKET_DISPLAY_NAME));String mimeType = albums.getString(albums.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE));Uri uri = getUri(albums);long count = countMap.get(bucketId);otherAlbums.addRow(new String[]{Long.toString(fileId),Long.toString(bucketId),bucketDisplayName,mimeType,uri.toString(),String.valueOf(count)});done.add(bucketId);totalCount += count;} while (albums.moveToNext());}}allAlbum.addRow(new String[]{Album.ALBUM_ID_ALL,Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null,allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(),String.valueOf(totalCount)});return new MergeCursor(new Cursor[]{allAlbum, otherAlbums});}}
二、AlbumCollection
AlbumCollection是作为AlbumLoader和MatisseActivity的中间层,实现了LoadManager.LoaderCallbacks接口,并通过自定义的AlbumCallbacks,将带数据的Cursor回调给MatisseActivity。
public interface AlbumCallbacks {void onAlbumLoad(Cursor cursor);void onAlbumReset();}
在onCreateLoader里创建了AlbumLoader的实例
@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {Context context = mContext.get();if (context == null) {return null;}mLoadFinished = false;return AlbumLoader.newInstance(context);}
在onLoadFinished里进行接口的回调
@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor data) {Context context = mContext.get();if (context == null) {return;}if (!mLoadFinished) {mLoadFinished = true;mCallbacks.onAlbumLoad(data);}}
同时也使用了onSaveInstanceState与onRestoreInstanceState进行状态的保存与恢复。
通过AlbumCollection这一层的封装,是的MatisseActivity里的代码更加简洁。
这篇关于Android进阶 -- 知乎Matisse源码解析(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!