Android进阶 -- 知乎Matisse源码解析(四)

2023-12-24 12:18

本文主要是介绍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源码解析(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/531746

相关文章

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

python常见环境管理工具超全解析

《python常见环境管理工具超全解析》在Python开发中,管理多个项目及其依赖项通常是一个挑战,下面:本文主要介绍python常见环境管理工具的相关资料,文中通过代码介绍的非常详细,需要的朋友... 目录1. conda2. pip3. uvuv 工具自动创建和管理环境的特点4. setup.py5.

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据