Android 文件管理器 文件缩略图标显示流程
前言
本篇文章是基于Android 11 文件管理器(com.android.documentsui)的源码,在实际项目中定位加载图片和视频文件显示缩略图的相关问题时,做的总结,文章中缩略图加载显示原理,查看过Android 10 和 12的源码,流程基本一致。
一、文件图标
文管在手机系统中扮演一个管理,分类,操作内部存储中所有类型文件的角色,把存储中的图片,音频,视频,文档,下载apk等各种文件通过归类整理,然后呈现给用户。
文档,音频,下载apk,其显示图标一般是对应的固定图标, 而图片和视频为了更好的区分其内容,展现给用户是缩略图, 如下图:
二. 显示原理
2.1 文管中界面显示框架也是采用 Activity + Fragment 实现的, 具体的Activity为:com.android.documentsui.files.FilesActivity.java Fragment为:com.android.documentsui.dirlist.DirectoryFragment.java
文管中文件显示有两种视图:MODE_GRID(网格模式) 和 MODE_LIST(列表模式)
每次点击一个菜单或者新进入一个文件夹,都会创建一个新的Fragment,然后替换之前的Fragment,好了,我们来具体看看这个DirectoryFragment.java文件:
整个界面显示是使用Recyclerview这个控件来完成的,核心代码如下:
./src/com/android/documentsui/dirlist/DirectoryFragment.java@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {mRecView = (RecyclerView) view.findViewById(R.id.dir_list);//当视图回收的时候,取消加载缩略图的taskmRecView.setRecyclerListener(new RecyclerListener() {@Overridepublic void onViewRecycled(ViewHolder holder) {cancelThumbnailTask(holder.itemView);}});//设置Item动画mRecView.setItemAnimator(new DirectoryItemAnimator());}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {// 适配器实例化 mAdapter = new DirectoryAddonsAdapter(mAdapterEnv,new ModelBackedDocumentsAdapter(mAdapterEnv, mIconHelper, mInjector.fileTypeLookup));// 设置适配器mRecView.setAdapter(mAdapter);// 这里的mColumnCount是通过calculateColumnCount(mode)计算得来,显示有几列// MODE_LIST视图下只显示1列mLayout = new GridLayoutManager(getContext(), mColumnCount) {@Overridepublic void onLayoutCompleted(RecyclerView.State state) {super.onLayoutCompleted(state);mFocusManager.onLayoutCompleted();}};//设置网格LayoutManagermRecView.setLayoutManager(mLayout);}
2.2 那数据信息是从哪里来的呢? 请留意DirectoryAddonsAdapter.java这个文件,我们知道:
RecyclerView显示View的控件,Adapter从模型层获取数据,然后提供给RecyclerView显示,它是沟通的桥梁。
Adapter的主要任务是:创建自定义的RecylerView.ViewHolder,然后将模型层的数据绑定到
ViewHolder上, 在实现上通常要复写以下三个方法:
1. onCreateViewHolder(ViewGroup parent, int viewType)
当需要新的ViewHolder来显示列表项时,会调用onCreateViewHolder方法去创建新的ViewHolder。
2. onBindViewHolder(CrimeHolder holder, int position)
将数据绑定在ViewHolder上。
3. getItemCount()
返回总共要显示的列表的数量
相关文件:
./src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java
./src/com/android/documentsui/dirlist/DocumentsAdapter.java
./src/com/android/documentsui/dirlist/DocumentHolder.java// 继承DocumentsAdapter
final class DirectoryAddonsAdapter extends DocumentsAdapter {}public abstract class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {}//元素载体
public abstract class DocumentHolderextends RecyclerView.ViewHolder implements View.OnKeyListener {/*** Binds the view to the given item data.* @param cursor* @param modelId* @param state*/// 此抽象方法在子类中去覆写,不同类型的文件加载不同的缩略图public abstract void bind(Cursor cursor, String modelId);}
2.3 与之相关的GridDocumentHolder.java类
相关文件
./src/com/android/documentsui/dirlist/GridDocumentHolder.java// 这里是网格模式下各个文件缩略图容器
final class GridDocumentHolder extends DocumentHolder {@Overridepublic void bind(Cursor cursor, String modelId) {assert(cursor != null);mModelId = modelId;mDoc.updateFromCursor(cursor, getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY));mIconHelper.stopLoading(mIconThumb);mIconMimeLg.animate().cancel();mIconMimeLg.setAlpha(1f);mIconThumb.animate().cancel();mIconThumb.setAlpha(0f);//缩略图加载显示的代码mIconHelper.load(mDoc, mIconThumb, mIconMimeLg, mIconMimeSm);}
}
2.4 最终加载是在ThumbnailLoader.java 类中完成的
相关文件:
./src/com/android/documentsui/dirlist/IconHelper.java
./src/com/android/documentsui/ThumbnailLoader.javapublic void load(Uri uri, String mimeType, int docFlags, int docIcon, long docLastModified,ImageView iconThumb, ImageView iconMime, @Nullable ImageView subIconMime) {if (showThumbnail) {loadedThumbnail =loadThumbnail(uri, docAuthority, docLastModified, iconThumb, iconMime);}}private boolean loadThumbnail(Uri uri, String docAuthority, long docLastModified,ImageView iconThumb, ImageView iconMime) {// 通过 ThumbnailLoader 这个task 去创建缩略图final ThumbnailLoader task = new ThumbnailLoader(uri, iconThumb,mCurrentSize, docLastModified,bitmap -> {if (bitmap != null) {iconThumb.setImageBitmap(bitmap);animator.accept(iconMime, iconThumb);}}, true /* addToCache */);ProviderExecutor.forAuthority(docAuthority).execute(task);}public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implements Preemptable {@Overrideprotected Bitmap doInBackground(Uri... params) {//返回缩略图的Bitmap对象}}
当然里面还有个缩略图的缓存机制,如果此文件已经创建过缩略图,下次可以直接从ThumbnailCache中拿出来,具体实现请查看源码文件ThumbnailCache.java
三、流程图
我们来梳理一下流程图:
四. 小结:
上述就是文件缩略图的显示流程,供大家参考!
1. 在实际项目中有时会遇到视频文件缩略图显示不出来的问题?
可能原因:DocumentsContract.getDocumentThumbnail(wrap(client), mUri, mThumbSize, mSignal)这个方法无法创建缩略图,返回为空。
解决方法:如果为空,我们可以通过传入文件路径然后生成缩略图,如下:
/*** 获取视频缩略图(获取第一帧)* @param filePath* @return bitmap*/public Bitmap getVideoThumbnail(String filePath) {Bitmap bitmap = null;MediaMetadataRetriever retriever = new MediaMetadataRetriever();try {retriever.setDataSource(filePath);bitmap = retriever.getFrameAtTime(TimeUnit.MILLISECONDS.toMicros(1));} catch(IllegalArgumentException e) {e.printStackTrace();} finally {try {retriever.release();}catch (RuntimeException e) {e.printStackTrace();}}return bitmap;}
2. 同一个视频文件,在不同文件夹显示的缩略图不一致的问题?
有时候外置SD卡/U盘 和 手机文件夹中的同一个视频,发现缩略图显示不一致现象,可以试试如下这个方法:获取视频中间的一帧来创建缩略图
/*** 获取视频的缩略图* 先通过ThumbnailUtils来创建一个视频的缩略图,然后再利用ThumbnailUtils来生成指定大小的缩略图。* 如果想要的缩略图的宽和高都小于MICRO_KIND,则类型要使用MICRO_KIND作为kind的值,这样会节省内存。* @param videoPath 视频的路径* @param width 指定输出视频缩略图的宽度* @param height 指定输出视频缩略图的高度度* @param kind 参照MediaStore.Images(Video).Thumbnails类中的常量MINI_KIND和MICRO_KIND。* 其中,MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96* @return 指定大小的视频缩略图*/public static Bitmap getVideoThumbnail(String videoPath, int width, int height,int kind) {Bitmap bitmap = null;// 获取视频的缩略图bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind); //調用ThumbnailUtils類的靜態方法createVideoThumbnail獲取視頻的截圖;if(bitmap!= null){bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);//調用ThumbnailUtils類的靜態方法extractThumbnail將原圖片(即上方截取的圖片)轉化為指定大小;}return bitmap;}
Android 文件管理器 文件缩略图标显示流程相关推荐
- Android10文件管理,10款优秀的Android文件管理器
本文将介绍10款Android文件管理器,包括:ES File Explorer.Dual File Manager XT.ASTRO File Manager,Ghost Commander,Fil ...
- android文件管理器项目,浅析Android文件管理器(项目一)
文件管理器是管理文件的软件,帮助用户处理日常工作,管理储存在本地和网络中的文件.所有文件管理器都提供了基本的操作如创建.打开.查看.编辑.移动和删除文件.许多Android文件管理器还提供了额外功能, ...
- 穿越派·派盘 + Solid Explorer = 全能 Android 文件管理器
Solid Explorer 是一款非常优秀的 Android 文件管理器,Material Design 设计风格,双栏布局,可拖拽操作.支持 ROOT 权限.多媒体浏览器.压缩包支持,Chrome ...
- android文件管理器listview,浅析Android文件管理器(项目一)
文件管理器是管理文件的软件,帮助用户处理日常工作,管理储存在本地和网络中的文件.所有文件管理器都提供了基本的操作如创建.打开.查看.编辑.移动和删除文件.许多Android文件管理器还提供了额外功能, ...
- android文件管理器项目,GitHub - yangsmith/FileExplorer: android file explorer android文件管理器...
File_Explorer Android 文件管理器 #发布版本 ####腾讯助手 ####百度助手 ####91助手 #包常用ui控件有: 1.侧滑菜单slidingMenu 2.兼容action ...
- 浅谈Android文件管理器的几种实现方式(原理篇)--对我有帮助
转自 https://blog.csdn.net/weixin_33698823/article/details/87269955 浅谈Android文件管理器的几种实现方式 为了完成毕业设计,我花费 ...
- android文件管理器u盘,Android U盘文件显示在文件管理器
在做物联网客户需求时,有客户要求实现u盘中的文件在文件管理器中显示,便于客户管理. 查看代码后,发现u盘是基于usb-otg挂载的,只要实现usb-otg文件显示在文件管理器中即可. android ...
- android文件管理器 xp,雨林木风XP系统es文件浏览器的使用
雨林木风XP系统es文件浏览器的使用,使用过es文件管理器的用户就知道es文件浏览器它的网络功能,就可以直接设置手机为一个小型的FTP服务器,使用这个FTP服务器,就能轻松把文件传输给在同一局域网下的 ...
- 史上最全Android文件管理器技术方案细节
前言: 这些都是基于市面上开源的文件管理器源码阅读提炼出来的思路,应用市场上绝大多数的文件管理器核心功能的实现其实大同小异,开源项目以小米社区开放版为主.如思路有错误希望大家提出一起商讨更好的思路. ...
- Android图形显示系统——一张图片的显示流程
Android设备上一张图片的显示过程 应用示例 假如我们现在有一张这样的风景照 想在Android设备(比如一个小米pad)上显示出来.首先想到的是写一个应用,用一个ImageView,把这张照片附 ...
最新文章
- SAP调用外部web service
- 【黑马程序员 C++教程从0到1入门编程】【笔记6】C++核心编程(文件操作)
- TFS突然链接不上(TF30063),并且MSN也连接不上,报主要端口的错误!
- GBDT 算法:原理篇
- MySQL日期时间转换函数
- xhEditor用法-可视化HTML编辑器
- 【C语言】扫雷游戏详解及完整代码
- 《走遍美国》MP3 共78集下载地址
- word打开文档很久很慢_word文档打开速度慢的几个原因和解决方法
- unable to close due to unfinalized statements or unfinished backups
- java 拼图_拼图延迟的历史-Oracle正式将Java 9的发布日期推迟到2017年
- 两条纵坐标折线图绘制
- linux 内存清理 释放命令,linux 内存清理释放命令(示例代码)
- aarch64-linux-gnu交叉编译器二进制方式安装
- AV/EDR 免杀逃避技术汇总
- 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 Xor
- 激光焊可以代替氩弧焊吗
- recurdyn和matlab联合仿真,recurdyn与simulink机电联合仿真,求助
- 详细的X-Scan使用教程
- 随机生成100以内加减法算式
热门文章
- 用户行为分析(Python)
- 基于jsp+java+ssm的大学生缴费系统
- 【Lesson 2】 大调音阶及大调和弦
- 三、任务切换之PendSV异常
- 使用BeautifulSoup,解释器报错‘lxml‘
- 微信小程序通过”链接/文字/数字等等“生成二维码
- DeFi 2.0的LaaS协议Elephant,重振DeFi赛道发展的关键
- 随笔小记--微博手动扩容来解决因新热搜“鹿晗关晓彤恋情”引起的down机
- 网络适配器网卡驱动错误代码56解决
- Windows窗口编程之计算机,WindowsAPI窗口程序设计.docx