前言

本篇文章是基于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 文件管理器 文件缩略图标显示流程相关推荐

  1. Android10文件管理,10款优秀的Android文件管理器

    本文将介绍10款Android文件管理器,包括:ES File Explorer.Dual File Manager XT.ASTRO File Manager,Ghost Commander,Fil ...

  2. android文件管理器项目,浅析Android文件管理器(项目一)

    文件管理器是管理文件的软件,帮助用户处理日常工作,管理储存在本地和网络中的文件.所有文件管理器都提供了基本的操作如创建.打开.查看.编辑.移动和删除文件.许多Android文件管理器还提供了额外功能, ...

  3. 穿越派·派盘 + Solid Explorer = 全能 Android 文件管理器

    Solid Explorer 是一款非常优秀的 Android 文件管理器,Material Design 设计风格,双栏布局,可拖拽操作.支持 ROOT 权限.多媒体浏览器.压缩包支持,Chrome ...

  4. android文件管理器listview,浅析Android文件管理器(项目一)

    文件管理器是管理文件的软件,帮助用户处理日常工作,管理储存在本地和网络中的文件.所有文件管理器都提供了基本的操作如创建.打开.查看.编辑.移动和删除文件.许多Android文件管理器还提供了额外功能, ...

  5. android文件管理器项目,GitHub - yangsmith/FileExplorer: android file explorer android文件管理器...

    File_Explorer Android 文件管理器 #发布版本 ####腾讯助手 ####百度助手 ####91助手 #包常用ui控件有: 1.侧滑菜单slidingMenu 2.兼容action ...

  6. 浅谈Android文件管理器的几种实现方式(原理篇)--对我有帮助

    转自 https://blog.csdn.net/weixin_33698823/article/details/87269955 浅谈Android文件管理器的几种实现方式 为了完成毕业设计,我花费 ...

  7. android文件管理器u盘,Android U盘文件显示在文件管理器

    在做物联网客户需求时,有客户要求实现u盘中的文件在文件管理器中显示,便于客户管理. 查看代码后,发现u盘是基于usb-otg挂载的,只要实现usb-otg文件显示在文件管理器中即可. android ...

  8. android文件管理器 xp,雨林木风XP系统es文件浏览器的使用

    雨林木风XP系统es文件浏览器的使用,使用过es文件管理器的用户就知道es文件浏览器它的网络功能,就可以直接设置手机为一个小型的FTP服务器,使用这个FTP服务器,就能轻松把文件传输给在同一局域网下的 ...

  9. 史上最全Android文件管理器技术方案细节

    前言: 这些都是基于市面上开源的文件管理器源码阅读提炼出来的思路,应用市场上绝大多数的文件管理器核心功能的实现其实大同小异,开源项目以小米社区开放版为主.如思路有错误希望大家提出一起商讨更好的思路. ...

  10. Android图形显示系统——一张图片的显示流程

    Android设备上一张图片的显示过程 应用示例 假如我们现在有一张这样的风景照 想在Android设备(比如一个小米pad)上显示出来.首先想到的是写一个应用,用一个ImageView,把这张照片附 ...

最新文章

  1. SAP调用外部web service
  2. 【黑马程序员 C++教程从0到1入门编程】【笔记6】C++核心编程(文件操作)
  3. TFS突然链接不上(TF30063),并且MSN也连接不上,报主要端口的错误!
  4. GBDT 算法:原理篇
  5. MySQL日期时间转换函数
  6. xhEditor用法-可视化HTML编辑器
  7. 【C语言】扫雷游戏详解及完整代码
  8. 《走遍美国》MP3 共78集下载地址
  9. word打开文档很久很慢_word文档打开速度慢的几个原因和解决方法
  10. unable to close due to unfinalized statements or unfinished backups
  11. java 拼图_拼图延迟的历史-Oracle正式将Java 9的发布日期推迟到2017年
  12. 两条纵坐标折线图绘制
  13. linux 内存清理 释放命令,linux 内存清理释放命令(示例代码)
  14. aarch64-linux-gnu交叉编译器二进制方式安装
  15. AV/EDR 免杀逃避技术汇总
  16. 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 Xor
  17. 激光焊可以代替氩弧焊吗
  18. recurdyn和matlab联合仿真,recurdyn与simulink机电联合仿真,求助
  19. 详细的X-Scan使用教程
  20. 随机生成100以内加减法算式

热门文章

  1. 用户行为分析(Python)
  2. 基于jsp+java+ssm的大学生缴费系统
  3. 【Lesson 2】 大调音阶及大调和弦
  4. 三、任务切换之PendSV异常
  5. 使用BeautifulSoup,解释器报错‘lxml‘
  6. 微信小程序通过”链接/文字/数字等等“生成二维码
  7. DeFi 2.0的LaaS协议Elephant,重振DeFi赛道发展的关键
  8. 随笔小记--微博手动扩容来解决因新热搜“鹿晗关晓彤恋情”引起的down机
  9. 网络适配器网卡驱动错误代码56解决
  10. Windows窗口编程之计算机,WindowsAPI窗口程序设计.docx