近期项目中需要从一个应用中拷贝一份文件(该文件无法直接拿到),并且文件放置的目录是data下,外部应用无法直接访问,所以考虑使用ContentProvider来实现。

ContentProvider,Android四大组件;ContentProvider 的作用是为不同的应用之间数据共享,提供统一的接口。本文就主要来说下实现样例。

一. 新建项目。相信大家都会了。

新建了两个项目,test01和test02。实例如下:

最终实现从test01的data目录下拷贝文件(data.xml)至test02中。

二.自定义实现ContentProvider。下面是代码展示:

/*** 文件共享*/
public class FileContentProvider extends ContentProvider {final private static String TAG = "FileContentProvider";//文件名称private static String FILENAME = "data.xml";@Overridepublic boolean onCreate() {Log.d(TAG, "========= onCreate is called =========");return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {Log.d(TAG, "========= query is called selection =========> " + selection);return null;}/*** 获取文件的文件名** @param uri* @return*/@Nullable@Overridepublic String getType(@NonNull Uri uri) {//判断文件是否存在String fileName = "";String path = MyApp.getContext().getFilesDir().getAbsolutePath();if (TextUtils.isEmpty(path)) {Log.i(TAG, "Data path must not be null!");ToastUtils.s(MyApp.getContext(), "Data path must not be null! ");fileName = "";return fileName;}File datapathFile = new File(path);if (!datapathFile.exists()) {Log.i(TAG, "Data path does not exist!");ToastUtils.s(MyApp.getContext(), "Data path does not exist! ");fileName = "";return fileName;}File datafile = new File(path + File.separator +FILENAME);if (!datafile.exists()) {Log.i(TAG, "Data file not found at " + datafile);ToastUtils.s(MyApp.getContext(), "Data file not found at " + datafile);fileName = "";return fileName;}fileName = FILENAME;Log.i(TAG, "fileName:" + FILENAME);Log.i(TAG, "uri.getPath():" + uri.getPath());return fileName;}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {return null;}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {return 0;}@Overridepublic int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {return 0;}/*** 需要实现该方法,** @param uri* @param mode* @return* @throws FileNotFoundException*/@Overridepublic ParcelFileDescriptor openFile(Uri uri, String mode)throws FileNotFoundException {String fileName = FILENAME;String filePath = MyApp.getContext().getFilesDir().getAbsolutePath() + File.separator + fileName;//如果存在文件,则获取文件相关信息,并返回File datafile = new File(filePath);if (datafile.exists()) {Log.i(TAG, " fileName: " + fileName);Log.i(TAG, "filePath: " + filePath);//计算文件的md5Log.i(TAG, "文件 file2MD5 " + Md5CaculateUtil.file2MD5(datafile));return ParcelFileDescriptor.open(datafile,ParcelFileDescriptor.MODE_READ_ONLY);} else {Log.d(TAG, "file not found at" + filePath);return null;}}}

说明:

1.重写了两个方法;

2.getType()方法 返回文件名称,openFile()方法返回文件流;

三. test01其他实现代码。

  private void goToTest02() {if (AppUtil.checkAppInstalled(MainActivity.this, SLF_PACKAGE_NAME)) {getFile();} else {ToastUtils.s(MainActivity.this, "应用未安装");}}/*** 获取文件*/private void getFile() {Intent intent = new Intent();ComponentName componeneName = new ComponentName(SLF_PACKAGE_NAME, SLF_ACTIVITY_NAME);intent.setComponent(componeneName);String filePath = MyApp.getContext().getFilesDir().getAbsolutePath() + File.separator + FILENAME;//如果存在文件,则获取文件的相关信息,并返回File datafile = new File(filePath);if (datafile.exists()) {Log.d(TAG, "文件存在");Log.i(TAG, " fileName: " + FILENAME);Log.i(TAG, "filePath: " + filePath);//计算文件的md5Log.i(TAG, "文件 file2MD5 " + Md5CaculateUtil.file2MD5(datafile));String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);Log.d(TAG, "文件的大小- fileSize is " + fileSize);intent.putExtra("fileName", FILENAME);startActivity(intent);return;}Log.d(TAG, "文件不存在");ToastUtils.s(MyApp.getContext(), "file not found at " + FILENAME);}

说明:

1. 先判断是否安装了test02应用;

2.判断是否存在需要共享的文件;

四. test02 部分实现代码,

   /****/private void getFileFromOutside() {Intent data = getIntent();if (data != null) {String fileName = data.getStringExtra("fileName");if (!TextUtils.isEmpty(fileName)) {Log.i(TAG, " fileName: " + fileName);readFile(fileName);} else {Log.i(TAG, "文件名未传递,请先核查是否有文件");}} else {Log.i(TAG, "getIntent() is null");}}/*** 通过getContentResolver 读取文件** @param fileName*/private void readFile(String fileName) {String filePath = getFilesDir().getAbsolutePath() + File.separator + fileName;File datafile = new File(filePath);//文件是否已经存在;如果存在,则不用再获取if (datafile.exists()) {Log.d(TAG, "file is exists");String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);Log.d(TAG, "文件的大小- fileSize is " + fileSize);//计算文件的md5Log.i(TAG, " 文件 file2MD5 " + Md5CaculateUtil.file2MD5(new File(filePath)));ToastUtils.s(MainActivity.this, "file is exists");return;}try {//通过contentprovide 获取文件名fileName = getContentResolver().getType(mUrl);if (TextUtils.isEmpty(fileName)) {Log.i(TAG, "fileName is null");return;}//通过contentprovide 获取文件InputStream is = getContentResolver().openInputStream(mUrl);// 获取文件路径filePath = getFilesDir().getAbsolutePath() + File.separator + fileName;OutputStream os = new FileOutputStream(new File(filePath));byte[] b = new byte[1024];int len;while ((len = is.read(b)) != -1) {os.write(b, 0, len);}os.flush();is.close();os.close();// 计算拷贝文件大小String fileSize = FileSizeUtil.getAutoFileOrFilesSize(filePath);Log.d(TAG, "-导入的 文件的大小- fileSize is " + fileSize);//计算文件的md5Log.i(TAG, "文件  file2MD5 " + Md5CaculateUtil.file2MD5(new File(filePath)));} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}

说明:

1.先判断文件是否存在;

2.调用ContentProvider提供的方法,从文件流中获取需要共享的文件,写入test02应用中。

3.其他代码详见源码。

4.上传文件“data.xml”至目录“/data/data/com.demo.test01/files”下。

5.运行后,日志,

test01和test02 源码和apk 下载地址。

五. 总结。

使用ContentProvider来达到应用见数据共享,需要自定义ContentProvider,重写相关方法;然后在应用中调用ContentProvider提供的外部调用方法。

ContentProvider 实战相关推荐

  1. 实战项目 10: 货物清单应用

    这篇文章分享我的 Android 开发(入门)课程 的最后一个实战项目:货物清单应用.这个项目托管在我的 GitHub 上,具体是 InventoryApp Repository,项目介绍已详细写在 ...

  2. 【开源推荐】进阶实战,从一款音乐播放器开始

    0.前言 前面有同学问我,想要做一个Android 实战项目,问我有没有好的开源项目可以参考和练习? 想想自己以前也是,当项目没有什么新任务的时候,想着自己写一个实战项目来来练练手,那拿什么项目来练手 ...

  3. 【码云周刊第 3 期】来自国内开发者的实战项目,开源让通讯从未如此简单!...

    为什么80%的码农都做不了架构师?>>>    类型:即时通讯 "小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头-- " 春节将至,思乡心切,小一情不自禁的想 ...

  4. 2022Android春招面试,实战分析

    前言 作为一个3-5年的Android工程师,我们经常会遇到这些瓶颈: 1.技术视野窄 长期在小型软件公司,外包公司工作,技术视野被限制的太厉害 2.薪资提升难 初中级Android岗位薪资上升空间有 ...

  5. Android实战开发Handler机制深度解析

    本文为自己多年来在Android实战开发过程中总结归纳的一些常见问题,现在分享出来希望对初学者有所帮助. 本文出自门心叼龙的博客,转载请注明出处: https://blog.csdn.net/gedu ...

  6. Android高级工程师技能知识储备,android实战项目源码

    二.显示 5.Ui(控件.事件处理) 窗口.视图 简单的基控件 复杂的组合控件 动画 事件及其传机制 三.存储 6.数据存储 Sharedpreferences Properties (java) F ...

  7. Google Android开发入门与实战

    Google Android开发入门与实战 [作 者]靳岩;姚尚朗 [同作者作品] [作译者介绍]  [出 版 社] 人民邮电出版社     [书 号] 9787115209306  [上架时间] 2 ...

  8. 《Google Android 开发入门与实战》

    <Google Android 开发入门与实战>(含1张DVD光盘) 市 场 价:¥55 书 号:9787115209306 出版日期:2009 年6月 开 本:16开 页码:340 [内 ...

  9. Google Android开发入门与实战 视频教程 源代码 游戏应用开发 传送门

    Google Android开发入门与实战 视频教程 视频目录 http://www.youku.com/playlist_show/id_5098662.html http://www.youku. ...

最新文章

  1. 转 java c++互传arraylist
  2. RabbitMQ学习总结(2)——安装、配置与监控
  3. 自制“低奢内”CSS3登入表单,包含JS验证,请别嫌弃哦。
  4. 关于 Taro 的 ScrollView 在Dom结构发生变化会自动回滚到顶部解决方案和原因
  5. ElasticSearch最全详细使用教程:入门、索引管理、映射详解
  6. 小米10首销战绩公布:嘴上说不买身体却很诚实
  7. 花书+吴恩达深度学习(六)优化方法之 Mini-batch(SGD, MBGD, BGD)
  8. 5复数与复变函数(五)
  9. python画图代码大全-Python Matplotlib 绘图使用指南 (附代码)
  10. android 5 1g内存,最新版:1G的RAM真的足够吗?使用软件测试Android手机的1G内存是否真的足够...
  11. poj1274 匈牙利算法 二分图最大匹配
  12. Django 入门初探
  13. python牛顿法寻找极值_使用Python实现牛顿法求极值
  14. 大学十年(一个程序员的路程)
  15. python爬虫之获取谷歌浏览器所有cookie
  16. 面向对象分析与设计--遛狗玩
  17. 没有处理程序要使用以下任何注释:javax.persistence.PersistenceContext
  18. PTA(Basic Level) 1024:科学计数法 (C语言实现)
  19. CIMPLICITY标签导入导出功能简单介绍
  20. (转载)分享一个昨天写的,3GQQ登录及取回sid的php源代码,内涵post/get访问网页的源代码。...

热门文章

  1. PCA主成分分析原理及分析实践详细介绍
  2. beetlsql官方文档
  3. 经纬度转高斯投影坐标(xy平面坐标)
  4. 谷歌浏览器怎么设置地址栏中使用百度搜索引擎
  5. uni-app基础(二)
  6. 微软分段推出电子墨水白板应用程序
  7. C语言字符串函数----strcat()函数用法
  8. wamp的apach打不开解决办法
  9. P问题、NP问题、NPC问题、NP难问题
  10. 有101根电线 每根的一头在楼底 另一端在楼顶 有一个灯泡 一个电池 无数根很短的电线 怎么样在楼上一次在楼下去一次将电线的对应关系弄清楚。