安卓之DocumentsProvider应用场景以及优劣分析

这篇具有很好参考价值的文章主要介绍了安卓之DocumentsProvider应用场景以及优劣分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章摘要

  本文深入探讨了安卓DocumentsProvider的应用场景,分析了其优势与不足,并提供了简单的代码实现。DocumentsProvider是安卓系统中用于文件存储与访问的关键组件,为应用开发者提供了强大的文件管理能力。

正文

DocumentsProvider概述

  DocumentsProvider是安卓系统中的一个组件,允许应用以统一的方式访问和管理文件。它作为存储访问框架(Storage Access Framework, SAF)的一部分,为开发者提供了一种简便、统一的方式来浏览和操作用户的文件,无需直接访问文件系统。

 

应用场景

文件浏览器

  文件管理器应用可以使用DocumentsProvider来访问和管理设备上的各种文件系统,包括内部存储、外部SD卡、云存储等。如Google的文件应用,

云服务集成

  云存储服务如Google DriveDropbox等可以通过实现DocumentsProvider来将其云存储空间集成到Android的文件选择器中,使得其他应用可以轻松地访问和操作云端文件。

自定义文件源

  对于需要展示非传统文件系统的应用(如网络文件、数据库内容等),可以通过实现自定义的DocumentsProvider来实现。

跨应用文件共享

  应用可以使用DocumentsProvider与其他应用共享文件,例如一个图片编辑应用可能需要通过DocumentsProvider来获取用户从图库或文件管理器中选择的图片。

备份和恢复功能

  应用可以使用DocumentsProvider来实现数据的备份和恢复功能,将用户数据保存到特定的位置,以便在需要时恢复。

优势分析

统一接口

  DocumentsProvider提供了标准化的接口来访问和管理文件,使得不同应用之间的文件交互更加简单和一致。

安全性

  通过SAF,应用可以请求用户授权以访问特定文件或文件夹,增强了用户隐私保护。

灵活性

  支持自定义的DocumentsProvider,可以扩展以支持各种非标准的文件源。

兼容性

  DocumentsProviderAndroid系统的一部分,因此在大多数Android设备上都能得到良好的支持。

支持多种文档类型

  DocumentsProvider 支持多种文档类型,如图片、视频、音频等,这使得开发人员可以更轻松地处理不同的文档类型。

遵循沙箱模型

  DocumentsProvider 遵循沙箱模型,这意味着每个应用程序只能访问其自己的文档,而不能访问其他应用程序的文档。这有助于保护用户的数据隐私。

易于使用

  DocumentsProvider 提供了一套简单易用的 API,使得开发人员可以轻松地实现文档浏览、编辑、存储等功能。

跨应用文件共享

  通过DocumentsProvider,应用可以方便地与其他应用共享文件,增强了用户体验和应用间的协作能力。

不足分析

版本兼容性

  早期版本的安卓可能不支持SAFDocumentsProvider

实现复杂性

  实现一个自定义的DocumentsProvider需要对内容提供者和文件系统有深入的理解,这可能会增加开发的复杂性和难度。

性能考虑

  对于大量文件的操作,如果不进行优化,可能会影响性能。

兼容性问题

  虽然DocumentsProviderAndroid系统的一部分,但在某些老旧或者定制的Android系统上可能存在兼容性问题。

缺乏对自定义文档的支持

  DocumentsProvider 不支持自定义文档类型,这意味着如果你的应用程序需要处理特定的文档类型,你可能需要实现自己的文档访问机制。

代码实现(示例)

文件浏览

  以下是一个简单的使用DocumentsProvider生成文件浏览器的代码实例。这个示例将展示如何创建一个基本的文件浏览Activity,该Activity可以列出由DocumentsProvider提供的文件和目录。

 

  首先,我们需要在AndroidManifest.xml中声明和注册我们的DocumentsProvider

<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />

 

<provider

    android:name=".FileBrowserDocumentsProvider"

    android:authorities="com.example.filebrowser.documentsprovider"

    android:exported="true"

android:grantUriPermissions="true"

    android:permission="android.permission.MANAGE_DOCUMENTS">

          <intent-filter>

              <action android:name="android.content.action.DOCUMENTS_PROVIDER" />

            </intent-filter>

            <meta-data

                android:name="android.content.extra.AUTHORITY"

                android:value="com.example.documentsprovider" />

</provider>

 

  然后,我们创建一个实现DocumentsProvider的类:

public class FileBrowserDocumentsProvider extends DocumentsProvider {

    private static final String ROOT_ID = "root";

 

    @Override

    public boolean onCreate() {

        return true;

    }

 

    @Nullable

    @Override

    public Cursor queryRoots(@Nullable String[] projection) throws FileNotFoundException {

        MatrixCursor cursor = new MatrixCursor(resolveRootProjection(projection));

 

        // 添加一个虚拟的根目录

        cursor.newRow()

                .add(ROOT_ID) // _id

                .add("Internal Storage") // document_id

                .add(null) // parent_document_id

                .add("internal_storage") // mime_type

                .add(R.drawable.ic_folder) // icon

                .add(true) // is_directory

                .add(false) // is_root

                .add(true) // is_virtual

                .add("") // display_name

                .add(getPathForDocId(ROOT_ID)) // summary

                .add(null); // capabilities

 

        return cursor;

    }

 

    @Nullable

    @Override

    public Cursor queryDocument(@NonNull String docId, @Nullable String[] projection) throws FileNotFoundException {

        // 实现查询单个文件或目录的逻辑

        // ...

    }

 

    @Nullable

    @Override

    public Cursor queryChildDocuments(@NonNull String parentDocId, @Nullable String[] projection, @Nullable String sortOrder) throws FileNotFoundException {

        // 实现查询子文件或子目录的逻辑

        // ...

    }

 

    @Nullable

    @Override

    public ParcelFileDescriptor openDocument(@NonNull String docId, @NonNull String mode, @Nullable CancellationSignal signal) throws FileNotFoundException {

        // 打开指定文档并返回ParcelFileDescriptor

        // ...

    }

 

    private String getPathForDocId(String docId) {

        // 根据docId获取对应的文件路径

        // ...

    }

 

    // 其他需要重写的方法...

}

 

  接下来,我们创建一个Activity来显示文件浏览器

public class FileBrowserActivity extends AppCompatActivity {

    private RecyclerView recyclerView;

    private FileBrowserAdapter adapter;

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_file_browser);

 

        recyclerView = findViewById(R.id.recycler_view);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        adapter = new FileBrowserAdapter();

        recyclerView.setAdapter(adapter);

 

        loadFiles();

    }

 

    private void loadFiles() {

        Uri uri = DocumentsContract.buildRootsUri(FileBrowserDocumentsProvider.AUTHORITY);

        CursorLoader cursorLoader = new CursorLoader(this, uri, null, null, null, null);

        cursorLoader.registerListener(0, new Loader.OnLoadCompleteListener<Cursor>() {

            @Override

            public void onLoadComplete(Loader<Cursor> loader, Cursor data) {

                adapter.swapCursor(data);

            }

        });

        cursorLoader.startLoading();

    }

 

    private class FileBrowserAdapter extends CursorAdapter {

        public FileBrowserAdapter() {

            super(FileBrowserActivity.this, null, 0);

        }

 

        @Override

        public View newView(Context context, Cursor cursor, ViewGroup parent) {

            View itemView = LayoutInflater.from(context).inflate(R.layout.item_file_browser, parent, false);

            return itemView;

        }

 

        @Override

        public void bindView(View view, Context context, Cursor cursor) {

            TextView textView = view.findViewById(R.id.text_view);

            textView.setText(cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME)));

 

            ImageView imageView = view.findViewById(R.id.image_view);

            int iconResId = cursor.getInt(cursor.getColumnIndex(DocumentsContract.Root.COLUMN_ICON));

            imageView.setImageResource(iconResId);

        }

    }

}

 

 

  在实际应用中,开发者需要根据自己的需求来扩展这些方法,以支持特定的文件操作和管理功能。

跨应用文件共享

  以下是一个使用DocumentsProvider实现跨应用文件共享的Java代码实例。这个示例将展示如何创建一个简单的DocumentsProvider,该提供者可以共享一个特定的文件夹给其他应用。

 

  首先,我们需要在AndroidManifest.xml中声明和注册我们的DocumentsProvider

<provider

    android:name=".FileSharingDocumentsProvider"

    android:authorities="com.example.filesharing.documentsprovider"

    android:exported="true" />

 

  然后,我们创建一个实现DocumentsProvider的类

public class FileSharingDocumentsProvider extends DocumentsProvider {

    private static final String AUTHORITY = "com.example.filesharing.documentsprovider";

    private static final String ROOT_ID = "root";

    private static final String SHARED_FOLDER_PATH = "/sdcard/shared_files";

 

    @Override

    public boolean onCreate() {

        return true;

    }

 

    @Nullable

    @Override

    public Cursor queryRoots(@Nullable String[] projection) throws FileNotFoundException {

        MatrixCursor cursor = new MatrixCursor(resolveRootProjection(projection));

 

        // 添加一个虚拟的根目录,指向我们要共享的文件夹

        cursor.newRow()

                .add(ROOT_ID) // _id

                .add("Shared Files") // document_id

                .add(null) // parent_document_id

                .add("vnd.android.document/directory") // mime_type

                .add(R.drawable.ic_folder) // icon

                .add(true) // is_directory

                .add(false) // is_root

                .add(true) // is_virtual

                .add("Shared Files") // display_name

                .add(SHARED_FOLDER_PATH) // summary

                .add(DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD); // capabilities

 

        return cursor;

    }

 

    @Nullable

    @Override

    public Cursor queryDocument(@NonNull String docId, @Nullable String[] projection) throws FileNotFoundException {

        // 实现查询单个文件或目录的逻辑

        // ...

    }

 

    @Nullable

    @Override

    public Cursor queryChildDocuments(@NonNull String parentDocId, @Nullable String[] projection, @Nullable String sortOrder) throws FileNotFoundException {

        if (ROOT_ID.equals(parentDocId)) {

            File sharedFolder = new File(SHARED_FOLDER_PATH);

            List<String> filesList = new ArrayList<>();

            for (File file : sharedFolder.listFiles()) {

                filesList.add(file.getName());

            }

 

            MatrixCursor cursor = new MatrixCursor(resolveDocumentProjection(projection));

            for (String fileName : filesList) {

                cursor.newRow()

                        .add(fileName) // _id

                        .add(fileName) // document_id

                        .add(ROOT_ID) // parent_document_id

                        .add(getMimeTypeForFile(fileName)) // mime_type

                        .add(0) // flags

                        .add(fileName) // display_name

                        .add("") // summary

                        .add(0); // size

            }

            return cursor;

        } else {

            throw new FileNotFoundException("Invalid parent document ID: " + parentDocId);

        }

    }

 

    @Nullable

    @Override

    public ParcelFileDescriptor openDocument(@NonNull String docId, @NonNull String mode, @Nullable CancellationSignal signal) throws FileNotFoundException {

        File file = new File(SHARED_FOLDER_PATH, docId);

        if (!file.exists()) {

            throw new FileNotFoundException("File not found: " + docId);

        }

 

        int fileMode = parseMode(mode);

        return ParcelFileDescriptor.open(file, fileMode);

    }

 

    private String getMimeTypeForFile(String fileName) {

        // 根据文件名获取对应的MIME类型

        // ...

    }

 

    private int parseMode(String mode) {

        // 将mode字符串(如"r"、"w"、"rw")转换为相应的ParcelFileDescriptor打开模式(如MODE_READ_ONLY、MODE_WRITE_ONLY、MODE_READ_WRITE)

        // ...

    }

 

    // 其他需要重写的方法...

}

 

  在这个示例中,我们创建了一个名为FileSharingDocumentsProvider的类,它继承自DocumentsProvider并实现了几个核心方法。这个提供者提供了一个虚拟的根目录,指向我们想要共享的文件夹(在这个例子中是"/sdcard/shared_files")。当我们查询这个根目录的子文档时,提供者会列出该文件夹中的所有文件,并返回它们的信息。

 

  现在,其他应用可以通过以下方式访问到这个共享文件夹。

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);

intent.addCategory(Intent.CATEGORY_OPENABLE);

intent.setType("*/*");

startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT);

在onActivityResult()方法中,你可以获取到用户选择的文件的Uri:

 

@Override

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == REQUEST_CODE_OPEN_DOCUMENT && resultCode == RESULT_OK && data != null) {

        Uri uri = data.getData();

        // 使用获取到的Uri进行文件操作

        // ...

    }

}

 

  请注意,这只是一个基础的示例,实际的DocumentsProvider可能需要处理更多的细节,例如权限控制、错误处理、文件操作等。此外,这个示例假设你已经有一个名为"/sdcard/shared_files"的文件夹,并且你的应用有读取和写入该文件夹的权限。在实际应用中,你需要根据你的需求和目标文件系统的特性来实现DocumentsProvider的相应方法。

总结

  DocumentsProvider为安卓应用开发者提供了一种强大而灵活的文件管理方式。通过了解其应用场景、优势与不足,并结合实际的代码实现,开发者可以更有效地利用这一工具来增强应用的文件管理功能。文章来源地址https://www.toymoban.com/news/detail-760391.html

到了这里,关于安卓之DocumentsProvider应用场景以及优劣分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 安卓之技术架构优劣分析

    安卓架构技术主要包括MVC、MVP、MVVM等。下面分别对这些架构技术进行分析优劣势,并附上代码示例。 MVC是一种常用的软件架构,它将应用程序分为三个主要组成部分:Model(模型)、View(视图)和Controller(控制器)。MVC架构可以通过将UI组件与业务逻辑分离来实现代码的模

    2024年02月04日
    浏览(9)
  • 安卓游戏开发之物理引擎优劣分析

    安卓游戏开发之物理引擎优劣分析

            在安卓游戏开发中,物理引擎是模拟现实世界中物理现象和技术的核心组件,它能够使得游戏中的物体和行为更加真实。物理引擎通常能够处理碰撞检测、动力学模拟、刚体、软体、关节、碰撞响应、摩擦力和更多物理效应。         不同的物理引擎有不同的

    2024年02月21日
    浏览(14)
  • 安卓游戏开发之图形渲染技术优劣分析

    安卓游戏开发之图形渲染技术优劣分析

            随着移动设备的普及和性能的提升,安卓游戏开发已经成为一个热门领域。在安卓游戏开发中,图形渲染技术是关键的一环。本文将对安卓游戏开发中常用的图形渲染技术进行分析,比较它们的优劣,并探讨它们在不同应用场景下的适用性。 2.1 、OpenGL ES      

    2024年02月20日
    浏览(17)
  • 详细分析Java中的Optional类以及应用场景

    详细分析Java中的Optional类以及应用场景

    在实战中学习,灵活运用每个操作类,具体如下: 源码主要如下: 大致含义如下: 这是一个容器对象,可能包含或不包含非空值。如果有值存在,isPresent() 方法将返回 true,而 get() 方法将返回该值。 提供了一些依赖于包含值的存在或缺失的其他方法,例如 orElse()(如果值不

    2024年04月27日
    浏览(18)
  • 详细分析Redis和Memcached的特点、应用场景以及区别

    Redis和Memcached是两种常用的内存缓存系统,用于提高数据访问的速度和性能。 Redis(Remote Dictionary Server)是一个开源的高性能键值存储系统(C语言编写),它支持多种数据结构,包括字符串、哈希表、列表、集合等,并提供了丰富的操作命令。 Redis的特点: 1. 数据持久化:

    2024年02月07日
    浏览(9)
  • 怎么通过Fiddler对APP进行抓包?以及高级应用场景分析

    怎么通过Fiddler对APP进行抓包?以及高级应用场景分析

    目录 前言 简单说下Fiddler的抓包原理: 使用fiddler代理远程捕获APP请求 Fiddler高级应用场景介绍 1、url地址重写  fiddler抓包详细教程:全网抓包天花板教程,B站讲的最详细的Fiddler/Charles抓包教学视频。2小时包你学会_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1tv4y1575S/?spm_id_from

    2024年02月08日
    浏览(12)
  • 24-函数缓存以及应用场景

    函数缓存,就是将函数运算过的结果进行缓存 本质上就是用空间(缓存存储)换时间(计算过程)。 常用于缓存数据计算结果和缓存对象 缓存只是一个临时的数据存储,它保存数据,以便将来对该数据的请求能够更快地得到处理 实现函数缓存主要依靠闭包、柯里化、高阶函

    2024年02月12日
    浏览(9)
  • 数学建模常用模型、特点以及应用场景

    1.层次分析法 特点: ①层次权重决策分析 ②较少的定量信息 ③多目标、多准则或无结构特性 ④适用于难以完全定量的复杂系统 例如:做出某种决策需要考虑多方面的因素 2.多属性决策模型 特点: ①利用已有的决策信息 ②对一组(有限个)备选方案进行排序或择优 ③属性权

    2024年02月01日
    浏览(11)
  • etcd概念及原理以及应用场景选型

    github:https://github.com/etcd-io/etcd 官方:https://etcd.io/ etcd是CoreOS团队于2013年6月发起的开源项目,授权协议为Apache。etcd是用于共享配置和服务发现的分布式,一致性的KV存储系统。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现 提供配置共享和服务发现的系统比较多,其

    2024年02月07日
    浏览(8)
  • WPF 与 Winform 的区别以及应用场景

    一、WPF框架以及应用场景 ​ WPF框架 ​ 1.1、WPF与WinForm ​ WPF :https://github.com/dotnet/wpf ​ SilverLight : Web富客户端 ​ 1.2、异/同点 ​ 共同点:最终的输出结果都是客户端应用,实现 人机交互。 ​ 异同点: ​ 界面渲染不一样 ​ 业务逻辑控制不一样(界面设计,色彩、尺寸比

    2024年02月09日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包