App磁盘沙盒工具实践
生活随笔
收集整理的這篇文章主要介紹了
App磁盘沙盒工具实践
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄介紹
- 01.磁盤沙盒的概述
- 1.1 項目背景說明
- 1.2 沙盒作用
- 1.3 設計目標
- 02.Android存儲概念
- 2.1 存儲劃分介紹
- 2.2 機身內部存儲
- 2.3 機身外部存儲
- 2.4 SD卡外部存儲
- 2.5 總結和梳理下
- 03.方案基礎設計
- 3.1 整體架構圖
- 3.2 UML設計圖
- 3.3 關鍵流程圖
- 3.4 接口設計圖
- 3.5 模塊間依賴關系
- 04.一些技術要點說明
- 4.1 使用隊列管理Fragment棧
- 4.2 File文件列表
- 4.3 不同版本訪問權限
- 4.4 訪問文件操作
- 4.5 10和11權限說明
- 4.6 分享文件給第三方
- 4.7 打開圖片資源
- 4.8 為何需要FileProvider
- 4.9 跨進程IPC通信
- 05.其他設計實踐說明
- 5.1 性能設計
- 5.2 穩定性設計
- 5.3 debug依賴設計
01.磁盤沙盒的概述
1.1 項目背景說明
- app展示在數據量多且刷新頻繁的情況下,為提升用戶體驗,通常會對上次已有數據做內存緩存或磁盤緩存,以達到快速展示數據的目的。緩存的數據變化是否正確、緩存是否起到對應作用是QA需要重點測試的對象。
- android緩存路徑查看方法有哪些呢?將手機打開開發者模式并連接電腦,在pc控制臺輸入cd /data/data/目錄,使用adb主要是方便測試(刪除,查看,導出都比較麻煩)。
- 如何簡單快速,傻瓜式的查看緩存文件,操作緩存文件,那么該項目小工具就非常有必要呢!采用可視化界面讀取緩存數據,方便操作,直觀也簡單。
1.2 沙盒作用
- 可以通過該工具查看緩存文件
- 快速查看data/data/包名目錄下的緩存文件。
- 快速查看/sdcard/Android/data/包名下存儲文件。
- 對緩存文件處理
- 支持查看file文件列表數據,打開緩存文件查看數據詳情。還可以刪除緩存對應的文件或者文件夾,并且友好支持分享到外部。
- 能夠查看緩存文件修改的信息,修改的時間,緩存文件的大小,獲取文件的路徑等等。都是在可視化界面上處理。
1.3 設計目標
- 可視化界面展示
- 多種處理文件操作
- 針對file文件夾,或者file文件,長按可以出現彈窗,讓測試選擇是否刪除文件。
- 點擊file文件夾,則拿到對應的文件列表,然后展示。點擊file直到是具體文件(文本,圖片,db,json等非file文件夾)跳轉詳情。
- 一鍵接入該工具
- FileExplorerActivity.startActivity(MainActivity.this);
- 開源項目地址:https://github.com/yangchong211/YCAndroidTool
02.Android存儲基本概念
2.1 存儲劃分介紹
- 存儲劃分介紹
- 手機空間存儲劃分為兩部分:1、機身存儲;2、SD卡外部存儲
- 機身存儲劃分為兩部分:1、內部存儲;2、外部存儲
- 機身內部存儲
- 放到data/data目錄下的緩存文件,一般使用adb無法查看該路徑文件,私有的。程序卸載后,該目錄也會被刪除。
- 機身外部存儲
- 放到/storage/emulated/0/目錄下的文件,有共享目錄,還有App外部私有目錄,還有其他目錄。App卸載的時候,相應的app創建的文件也會被刪除。
- SD卡外部存儲
- 放到sd庫中目錄下文件,外部開放的文件,可以查看。
2.2 機身內部存儲
- 想一下平時使用的持久化方案:這些文件都是默認放在內部存儲里。
- SharedPreferences---->適用于存儲小文件
- 數據庫---->存儲結構比較復雜的大文件
- 如果包名為:com.yc.helper,則對應的內部存儲目錄為:/data/data/com.yc.helper/
- 第一個"/“表示根目錄,其后每個”/"表示目錄分割符。內部存儲里給每個應用按照其包名各自劃分了目錄
- 每個App的內部存儲空間僅允許自己訪問(除非有更高的權限,如root),程序卸載后,該目錄也會被刪除。
- 機身內部存儲一般存儲那些文件呢?大概有以下這些
- cache–>存放緩存文件
- code_cache–>存放運行時代碼優化等產生的緩存
- databases–>存放數據庫文件
- files–>存放一般文件
- lib–>存放App依賴的so庫 是軟鏈接,指向/data/app/ 某個子目錄下
- shared_prefs–>存放 SharedPreferences 文件
- 那么怎么通過代碼訪問到這些路徑的文件呢?代碼如下所示context.getCacheDir().getAbsolutePath() context.getCodeCacheDir().getAbsolutePath() //databases 直接通過getDatabasePath(name)獲取 context.getFilesDir().getAbsolutePath() //lib,暫時還不知道怎么獲取該路徑 //shared_prefs 直接通過SharedPreferences獲取
2.3 機身外部存儲
- 存放位置,主要有那些?如下所示,根目錄下幾個需要關注的目錄:
- /data/ 這個是前面說的私有文件
- /sdcard/ /sdcard/是軟鏈接,指向/storage/self/primary
- /storage/ /storage/self/primary/是軟鏈接,指向/storage/emulated/0/
- 也就是說/sdcard/、/storage/self/primary/ 真正指向的是/storage/emulated/0/
- 下面這個是用adb查看 /storage/emulated/0 路徑資源
- 然后來看下 /storage/emulated/0/ 存儲的資源有哪些?如下,分為三部分:
- 第一種:共享存儲空間
- 也就是所有App共享的部分,比如相冊、音樂、鈴聲、文檔等:
- DCIM/ 和 Pictures/–>存儲圖片
- DCIM/、Movies/ 和 Pictures–>存儲視頻
- Alarms/、Audiobooks/、Music/、Notifications/、Podcasts/ 和 Ringtones/–>存儲音頻文件
- Download/–>下載的文件
- Documents–>存儲如.pdf類型等文件
- 第二種:App外部私有目錄
- Android/data/—>存儲各個App的外部私有目錄。
- 與內部存儲類似,命名方式是:Android/data/xx------>xx指應用的包名。如:/sdcard/Android/data/com.yc.helper
- 第三種:其它目錄
- 比如各個App在/sdcard/目錄下創建的目錄,如支付寶創建的目錄:alipay/,高德創建的目錄:amap/,騰訊創建的目錄:com.tencent.xx/等。
- 那么怎么通過代碼訪問到這些路徑的文件呢?代碼如下所示
- 第一種:通過ContentProvider訪問,共享存儲空間中的圖片,視頻,音頻,文檔等資源
- 第二種:可以看出再/sdcard/Android/data/目錄下生成了com.yc.helper/目錄,該目錄下有兩個子目錄分別是:files/、cache/。當然也可以選擇創建其它目錄。App卸載的時候,兩者都會被清除。
- 第三種:只要拿到根目錄,就可以遍歷尋找其它子目錄/文件。
2.4 SD卡外部存儲
- 當給設備插入SD卡后,查看其目錄:/sdcard/ —> 依然指向/storage/self/primary,繼續來看/storage/,可以看出,多了sdcard1,軟鏈接指向了/storage/77E4-07E7/。
- 訪問方式,跟獲取外部存儲-App私有目錄方式一樣。File[] fileList = context.getExternalFilesDirs(null);
- 返回File對象數組,當有多個外部存儲時候,存儲在數組里。返回的數組有兩個元素,一個是自帶外部存儲存儲,另一個是插入的SD卡。
2.5 總結和梳理下
- Android存儲有三種:手機內部存儲、手機自帶外部存儲、SD卡擴展外部存儲等。
- 內部存儲與外部存儲里的App私有目錄
- 相同點:
- 1、屬于App專屬,App自身訪問兩者無需任何權限。
- 2、App卸載后,兩者皆被刪除。
- 3、兩者目錄下增加的文件最終會被統計到"設置->存儲和緩存"里。
- 不同點:
- /data/data/com.yc.helper/ 位于內部存儲,一般用于存儲容量較小的,私密性較強的文件。
- 而/sdcard/Android/data/com.yc.helper/ 位于外部存儲,作為App私有目錄,一般用于存儲容量較大的文件,即使刪除了也不影響App正常功能。
- 相同點:
- 在設置里的"存儲與緩存"項,有清除數據和清除緩存,兩者有何區別?
- 當點擊"清除數據" 時:
- 內部存儲/data/data/com.yc.helper/cache/、 /data/data/com.yc.helper/code_cache/目錄會被清空
- 外部存儲/sdcard/Android/data/com.yc.helper/cache/ 會被清空
- 當點擊"清除緩存" 時:
- 內部存儲/data/data/com.yc.helper/下除了lib/,其余子目錄皆被刪除
- 外部存儲/sdcard/Android/data/com.yc.helper/被清空
- 這種情況,相當于刪除用戶sp,數據庫文件,相當于重置了app
- 當點擊"清除數據" 時:
04.一些技術要點說明
4.1 使用隊列管理Fragment棧
- 該磁盤沙盒file工具頁面的組成部分是這樣的
- FileExplorerActivity + FileExplorerFragment(多個,file列表頁面) + TextDetailFragment(一個,file詳情頁面)
- 針對磁盤file文件列表FileExplorerFragment頁面,點擊file文件item
- 如果是文件夾則是繼續打開跳轉到file文件列表FileExplorerFragment頁面,否則跳轉到文件詳情頁面
- 處理任務棧返回邏輯。舉個例子現在列表FileExplorerFragment當作B,文件詳情頁面當作C,宿主Activity當作A。也就是說,點擊返回鍵,依次關閉了fragment直到沒有,回到宿主activity頁面。再次點擊返回鍵,則關閉activity!
- 可能存在的任務棧是:打開A1->打開B1->打開C1
- 那么點擊返回鍵按鈕,返回關閉的順序則是:關閉C1->關閉B1->關閉A1
- Fragment回退棧處理方式
- 第一種方案:創建一個棧(先進后出),打開一個FileExplorerFragment列表頁面(push一個fragment對象到隊列中),關閉一個列表頁面(remove最上面那個fragment對象,然后調用FragmentManager中popBackStack操作關閉fragment)
- 第二種方案:通過fragmentManager獲取所有fragment對象,返回一個list,當點擊返回的時候,調用popBackStack移除最上面一個
- 具體處理該場景中回退邏輯
- 首先定義一個雙端隊列ArrayDeque,用來存儲和移除元素。內部使用數組實現,可以當作棧來使用,功能非常強大。
- 當開啟一個fragment頁面的時候,調用push(相當于addFirst在棧頂添加元素)來存儲fragment對象。代碼如下所示public void showContent(Class<? extends Fragment> target, Bundle bundle) {try {Fragment fragment = target.newInstance();if (bundle != null) {fragment.setArguments(bundle);}FragmentManager fm = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fm.beginTransaction();fragmentTransaction.add(android.R.id.content, fragment);//push等同于addFirst,添加到第一個mFragments.push(fragment);//add等同于addLast,添加到最后//mFragments.add(fragment);fragmentTransaction.addToBackStack("");//將fragment提交到任務棧中fragmentTransaction.commit();} catch (InstantiationException exception) {FileExplorerUtils.logError(TAG + exception.toString());} catch (IllegalAccessException exception) {FileExplorerUtils.logError(TAG + exception.toString());} }
- 當關閉一個fragment頁面的時候,調用removeFirst(相當于彈出棧頂的元素)移除fragment對象。代碼如下所示@Override public void onBackPressed() {if (!mFragments.isEmpty()) {Fragment fragment = mFragments.getFirst();if (fragment!=null){//移除最上面的一個mFragments.removeFirst();}super.onBackPressed();//如果fragment棧為空,則直接關閉activityif (mFragments.isEmpty()) {finish();}} else {super.onBackPressed();} }/*** 回退fragment任務棧操作* @param fragment fragment*/ public void doBack(Fragment fragment) {if (mFragments.contains(fragment)) {mFragments.remove(fragment);FragmentManager fm = getSupportFragmentManager();//回退fragment操作fm.popBackStack();if (mFragments.isEmpty()) {//如果fragment棧為空,則直接關閉宿主activityfinish();}} }
4.2 File文件列表
- 獲取文件列表,主要包括,data/data/包名目錄下的緩存文件。/sdcard/Android/data/包名下存儲文件。/*** 初始化默認文件。注意:加External和不加(默認)的比較* 相同點:1.都可以做app緩存目錄。2.app卸載后,兩個目錄下的數據都會被清空。* 不同點:1.目錄的路徑不同。前者的目錄存在外部SD卡上的。后者的目錄存在app的內部存儲上。* 2.前者的路徑在手機里可以直接看到。后者的路徑需要root以后,用Root Explorer 文件管理器才能看到。** @param context 上下文* @return 列表*/ private List<File> initDefaultRootFileInfos(Context context) {List<File> fileInfos = new ArrayList<>();//第一個是文件父路徑File parentFile = context.getFilesDir().getParentFile();if (parentFile != null) {fileInfos.add(parentFile);}//路徑:/data/user/0/com.yc.lifehelper//第二個是緩存文件路徑File externalCacheDir = context.getExternalCacheDir();if (externalCacheDir != null) {fileInfos.add(externalCacheDir);}//路徑:/storage/emulated/0/Android/data/com.yc.lifehelper/cache//第三個是外部file路徑File externalFilesDir = context.getExternalFilesDir((String) null);if (externalFilesDir != null) {fileInfos.add(externalFilesDir);}//路徑:/storage/emulated/0/Android/data/com.yc.lifehelper/filesreturn fileInfos; }
4.3 不同版本訪問權限
- Android 6.0 之前訪問方式
- Android 6.0 之前是無需申請動態權限的,在AndroidManifest.xml 里聲明存儲權限。就可以訪問共享存儲空間、其它目錄下的文件。
- Android 6.0 之后的訪問方式
- Android 6.0 后需要動態申請權限,除了在AndroidManifest.xml 里聲明存儲權限外,還需要在代碼里動態申請。
4.4 訪問文件操作
- 權限申請成功后,即可對自帶外部存儲之共享存儲空間和其它目錄進行訪問。分別以共享存儲空間和其它目錄為例,闡述訪問方式:
- 訪問媒體文件(共享存儲空間)。目的是拿到媒體文件的路徑,有兩種方式獲取路徑:
- 以圖片為例,假設圖片存儲在/sdcard/Pictures/目錄下。路徑:/storage/emulated/0/Pictures/yc.png,拿到路徑后就可以解析并獲取Bitmap。
- 通過MediaStore獲取路徑
- 還有一種不直接通過路徑訪問的方法,通過MediaStore獲取Uri。與直接拿到路徑不同的是,此處拿到的是Uri。圖片的信息封裝在Uri里,通過Uri構造出InputStream,再進行圖片解碼拿到Bitmap
- 訪問文檔和其它文件(共享存儲空間)。
- 直接構造路徑。與媒體文件一樣,可以直接構造路徑訪問。
- 訪問其它目錄
- 直接構造路徑。與媒體文件一樣,可以直接構造路徑訪問。
- 總結一下共同點
- 訪問目錄/文件可通過如下兩個方法:1、通過路徑訪問。路徑可以直接構造也可以通過MediaStore獲取。 2、通過Uri訪問。Uri可以通過MediaStore或者SAF(存儲訪問框架,通過intent調用startActivity訪問)獲取。
4.5 10和11權限說明
- Android10權限改變
- 比如能夠直接在/sdcard/目錄下創建目錄/文件。可以看出/sdcard/目錄下,如淘寶、qq、qq瀏覽器、微博、支付寶等都自己建了目錄。
- 這么看來,導致目錄結構很亂,而且App卸載后,對應的目錄并沒有刪除,于是就是遺留了很多"垃圾"文件,久而久之不處理,用戶的存儲空間越來越小。
- 之前文件創建弊端如下
- 卸載App也不能刪除該目錄下的文件
- 在設置里"清除數據"或者"清除緩存"并不能刪除該目錄下的文件
- App可以隨意修改其它目錄下的文件,如修改別的App創建的文件等,不安全
- 為什么要在/sdcard/目錄下新建app存儲的目錄
- 此處新建的目錄不會被設置里的App存儲用量統計,讓用戶"看起來"自己的App占用的存儲空間很小。還有就是方便操作文件
- Android 10.0訪問變更
- Google在Android 10.0上重拳出擊了。引入Scoped Storage。簡單來說有好幾個版本:作用域存儲、分區存儲、沙盒存儲。分區存儲原理:
- 1、App訪問自身內部存儲空間、訪問外部存儲空間-App私有目錄不需要任何權限(這個與Android 10.0之前一致)
- 2、外部存儲空間-共享存儲空間、外部存儲空間-其它目錄 App無法通過路徑直接訪問,不能新建、刪除、修改目錄/文件等
- 3、外部存儲空間-共享存儲空間、外部存儲空間-其它目錄 需要通過Uri訪問
4.6 分享文件給第三方
- 這里直接說分享內部文件給第三方,大概的思路如下所示:
- 第一步:先判斷是否有讀取文件的權限,如果沒有則申請;如果有則進行第二步;
- 第二步:先把文件轉移到外部存儲文件,為何要這樣操作,主要是解決data/data下目前文件無法直接分享問題,因此需要將目標文件拷貝到外部路徑
- 第三步:通過intent發送,FileProvider拿到對應路徑的uri,最后調用startActivity進行分享文件。
- 大概的代碼如下所示if (ContextCompat.checkSelfPermission(mActivity,Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(mActivity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE); } else {//先把文件轉移到外部存儲文件File srcFile = new File(mFile.getPath());String newFilePath = AppFileUtils.getFileSharePath() + "/fileShare.txt";File destFile = new File(newFilePath);//拷貝文件,將data/data源文件拷貝到新的目標文件路徑下boolean copy = AppFileUtils.copyFile(srcFile, destFile);if (copy) {//分享boolean shareFile = FileShareUtils.shareFile(mActivity, destFile);if (shareFile) {Toast.makeText(getContext(), "文件分享成功", Toast.LENGTH_SHORT).show();} else {Toast.makeText(getContext(), "文件分享失敗", Toast.LENGTH_SHORT).show();}} else {Toast.makeText(getContext(), "文件保存失敗", Toast.LENGTH_SHORT).show();} }
4.7 打開圖片資源
- 首先判斷文件,是否是圖片資源,如果是圖片資源,則跳轉到打開圖片詳情。目前只是根據文件的后綴名來判斷(對文件名稱以.進行裁剪獲取后綴名)是否是圖片。if (FileExplorerUtils.isImage(fileInfo)) {Bundle bundle = new Bundle();bundle.putSerializable("file_key", fileInfo);showContent(ImageDetailFragment.class, bundle); }
- 打開圖片跳轉詳情,這里面為了避免打開大圖OOM,因此需要對圖片進行壓縮,目前該工具主要是內存壓縮和尺寸縮放方式。大概的原理如下
- 例如,我們的原圖是一張 2700 * 1900 像素的照片,加載到內存就需要 19.6M 內存空間,但是,我們需要把它展示在一個列表頁中,組件可展示尺寸為 270 * 190,這時,我們實際上只需要一張原圖的低分辨率的縮略圖即可(與圖片顯示所對應的 UI 控件匹配),那么實際上 270 * 190 像素的圖片,只需要 0.2M 的內存即可。這個采用縮放比壓縮。
- 加載圖片,先加載到內存,再進行操作嗎,可以如果先加載到內存,好像也不太對,這樣只接占用了 19.6M + 0.2M 2份內存了,而我們想要的是,在原圖不加載到內存中,只接將縮放后的圖片加載到內存中,可以實現嗎?
- 進行內存壓縮,要將BitmapFactory.Options的inJustDecodeBounds屬性設置為true,解析一次圖片。注意這個地方是核心,這個解析圖片并沒有生成bitmap對象(也就是說沒有為它分配內存控件),而僅僅是拿到它的寬高等屬性。
- 然后將BitmapFactory.Options連同期望的寬度和高度一起傳遞到到calculateInSampleSize方法中,就可以得到合適的inSampleSize值了。這一步會壓縮圖片。之后再解析一次圖片,使用新獲取到的inSampleSize值,并把inJustDecodeBounds設置為false,就可以得到壓縮后的圖片了。
4.8 為何需要FileProvider
4.8.1 文件共享基礎概念
- 了解文件共享的基礎知識
-
提到文件共享,首先想到就是在本地磁盤上存放一個文件,多個應用都可以訪問它,如下:
-
理想狀態下只要知道了文件的存放路徑,那么各個應用都可以讀寫它。比如相冊里的圖片或者視頻存放目錄:/sdcard/DCIM/、/sdcard/Pictures/ 、/sdcard/Movies/。
-
- 文件共享方式是如何理解
- 一個常見的應用場景:應用A里檢索到一個文件yc.txt,它無法打開,于是想借助其它應用打開,這個時候它需要把待打開的文件路徑告訴其它應用。對應案例就是,把磁盤文件分享到qq。
- 這就涉及到了進程間通信。Android進程間通信主要手段是Binder,而四大組件的通信也是依靠Binder,因此我們應用間傳遞路徑可以依靠四大組件。
4.8.2 7.0前后對文件處理方式
- Android 7.0 之前使用,傳遞路徑可以通過UriIntent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
//通過路徑,構造Uri。設置Intent,附帶Uri,然后通過intent跨進程通信
Uri uri = Uri.fromFile(new File(external_filePath));
intent.setData(uri);
startActivity(intent);
- 接收方在收到Intent后,拿出Uri,通過:filePath = uri.getEncodedPath() 拿到發送方發送的原始路徑后,即可讀寫文件。然而此種構造Uri方式在Android7.0(含)之后被禁止了,若是使用則拋出異常,異常是FileUriExposedException。
- 這種方式缺點如下:第一發送方傳遞的文件路徑接收方完全知曉,一目了然,沒有安全保障;第二發送方傳遞的文件路徑接收方可能沒有讀取權限,導致接收異常。
- Android 7.0(含)之后如何解決上面兩個缺點問題
- 對第一個問題:可以將具體路徑替換為另一個字符串,類似以前密碼本的感覺,比如:"/storage/emulated/0/com.yc.app/yc.txt" 替換為"file/yc.txt",這樣接收方收到文件路徑完全不知道原始文件路徑是咋樣的。那么會導致另一個額外的問題:接收方不知道真實路徑,如何讀取文件呢?
- 對第二個問題既然不確定接收方是否有打開文件權限,那么是否由發送方打開,然后將流傳遞給接收方就可以了呢?
- Android 7.0(含)之后引入了FileProvider,可以解決上述兩個問題。
4.8.3 FileProvider應用與原理
- 第一步,定義自定義FileProvider并且注冊清單文件public class ExplorerProvider extends FileProvider {}<!--既然是ContentProvider,那么需要像Activity一樣在AndroidManifest.xml里聲明:--> <!--android:authorities 標識ContentProvider的唯一性,可以自己任意定義,最好是全局唯一的。--> <!--android:name 是指之前定義的FileProvider 子類。--> <!--android:exported="false" 限制其他應用獲取Provider。--> <!--android:grantUriPermissions="true" 授予其它應用訪問Uri權限。--> <!--meta-data 囊括了別名應用表。--> <!--android:name 這個值是固定的,表示要解析file_path--> <!--android:resource 自己定義實現的映射表--> <providerandroid:name="com.yc.toolutils.file.ExplorerProvider"android:authorities="${applicationId}.fileExplorerProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_explorer_provider" /> </provider>
- 第二步,添加路徑映射表
- 在/res/ 下建立xml 文件夾,然后再創建對應的映射表(xml),最終路徑如下:/res/xml/file_explorer_provider.xml。
- 第三步,使用ExplorerProvider來跨進程通信交互
- 如何解決第一個問題,讓接收方看不到具體文件的路徑?如下所示,下面構造后,第三方應用收到此Uri后,并不能從路徑看出我們傳遞的真實路徑,這就解決了第一個問題。
- 如何解決第二個問題,發送方傳遞的文件路徑接收方可能沒有讀取權限,導致接收異常?通過FileProvider.getUriForFile為入口查看源碼,應用間通過IPC機制,最后調用了openFile()方法,而FileProvider重寫了該方法。
4.9 跨進程IPC通信
- A應用(該demo)通過構造Uri,通過intent調用B(分享到QQ)
- 應用A將path構造為Uri:應用A在啟動的時候,會掃描AndroidManifest.xml 里的 FileProvider,并讀取映射表構造為一個Map。
- 還是以/storage/emulated/0/com.yc.lifehelper.fileExplorerProvider/external_path/fileShare.txt 為例,當調用 FileProvider.getUriForFile(xx)時,遍歷Map,找到最匹配條目,最匹配的即為external_file。因此會用external_file 代替原始路徑,最終形成的Uri為:content://com.yc.lifehelper.fileExplorerProvider/external_path/fileShare.txt
- B應用(QQ)通過Uri構造輸入流,將Uri解析成具體的路徑
- 應用B通過Uri(A傳遞過來的),解析成具體的file文件。先將Uri分離出external_file/fileShare.txt,然后通過external_file 從Map里找到對應Value 為:/storage/emulated/0/com.yc.lifehelper.fileExplorerProvider/,最后將fileShare.txt拼接,形成的路徑為:/storage/emulated/0/com.yc.lifehelper.fileExplorerProvider/external_path/fileShare.txt
- 現在來梳理整個流程:
- 1、應用A使用FileProvider通過Map(映射表)將Path轉為Uri,通過IPC 傳遞給應用B。
- 2、應用B使用Uri通過IPC獲取應用A的FileProvider。
- 3、應用A使用FileProvider通過映射表將Uri轉為Path,并構造出文件描述符。
- 4、應用A將文件描述符返回給應用B,應用B就可以讀取應用A發送的文件了。
- 整個交互流程圖如下
05.其他設計實踐說明
5.1 性能設計
- 這個暫無,因為是小工具,主要是在debug環境下依賴使用。代碼邏輯并不復雜,不會影響App的性能。
5.2 穩定性設計
- 修改文件說明
- 目前,針對文本文件,比如緩存的json數據,存儲在文本文件中,之前測試說讓該工具支持修改屬性,考慮到修改json比較復雜,因此這里只是實現可以刪除文本文件,或者修改文件名稱的功能。
- 針對圖片文件,可以打開且進行了圖片壓縮,僅僅支持刪除圖片文件操作。
- 針對sp存儲的數據,是xml,這里可視化展示sp的數據,目前可以支持修改sp數據,測試童鞋這方便操作簡單,提高某些場景的測試效率。
- 為何不支持修改json
- 讀取文本文件,是一行行讀取,修改數據編輯數據麻煩,而且修改完成后對json數據合法性判斷也比較難處理。因此這里暫時不提供修改緩存的json數據,測試如果要看,可以通過分享到外部qq查看文件,或者直接查看,避免臟數據。
5.3 debug依賴設計
- 建議在debug下使用
- 在小工具放到debug包名下,依賴使用。或者在gradle依賴的時候區分也可以。如下所示:
總結
以上是生活随笔為你收集整理的App磁盘沙盒工具实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文总结 -论文写作注意事项(持续更)
- 下一篇: LaTeX - 毕业答辩Beamer