Android10分區(qū)存儲(chǔ)適配

這個(gè)問(wèn)題其實(shí)在很早之前Android10提出的時(shí)候就開(kāi)始做了適配矾睦,但是為什么寫(xiě)這篇文章呢痒筒,是因?yàn)锳ndroid11快來(lái)了反症,目前我們這邊沒(méi)有android11的手機(jī)進(jìn)行測(cè)試贼邓,所以會(huì)產(chǎn)生一些疑問(wèn)塑径,打算寫(xiě)出來(lái)统舀,希望能有大佬們指點(diǎn)一二誉简。

廢話不多說(shuō)闷串,直接開(kāi)始。
android 10提出了分區(qū)存儲(chǔ)的概念碉熄。開(kāi)發(fā)者無(wú)法直接獲取外部存儲(chǔ)的讀寫(xiě)權(quán)限锈津,用我們平常的話來(lái)說(shuō)就是無(wú)法直接讀寫(xiě)SD卡上的東西一姿。
可以看看官方的描述:https://developer.android.com/training/data-storage/files/external-scoped

這是什么意思呢,別急爆存,我們按照一些場(chǎng)景來(lái)舉例携冤,讓你能夠大概知道Android10這種環(huán)境下如何進(jìn)行適配菜循。

一. 場(chǎng)景舉例

PS:如果不知道分區(qū)存儲(chǔ)是什么個(gè)情況癌幕,建議在Android11的手機(jī)上并設(shè)置targetSdkVersion為29橙喘,跑一遍應(yīng)用,寫(xiě)個(gè)讀寫(xiě)外部存儲(chǔ)的操作和簸,看看會(huì)發(fā)生什么

1. 目標(biāo)版本targetSdkVersion設(shè)置為29以下的情況

這種情況下能正常的讀寫(xiě)SD卡的文件,也就是Environment.getExternalStorageDirectory()路徑的文件,我很早之前測(cè)試過(guò)霉赡,好像我記得即便手機(jī)是Android10幔托,只要targetSdkVersion不設(shè)置超過(guò)29也不會(huì)有外部存儲(chǔ)的讀寫(xiě)問(wèn)題(不對(duì)的話請(qǐng)指出)
如果是這樣的話重挑,最方便的做法就是不把targetSdkVersion設(shè)置超過(guò)29就不會(huì)有問(wèn)題

2. 使用應(yīng)用自身的外部存儲(chǔ)路徑

使用應(yīng)用自身的外部存儲(chǔ)不會(huì)受影響谬哀,只不過(guò)這個(gè)路徑的文件會(huì)在卸載時(shí)也會(huì)被刪除谦屑。
簡(jiǎn)單來(lái)說(shuō)就是context.getExternalFilesDir()不受影響, Environment.getExternalStorageDirectory()才受影響帘睦。

3. 如何文件再升級(jí)前已經(jīng)存在的情況

怎么去了解這種情況涝焙,我舉個(gè)栗子,手機(jī)是Android10隧哮,假如第一次裝的應(yīng)用的targetSdkVersion是28桶良,此時(shí)是能正常使用原本的Environment.getExternalStorageDirectory()對(duì)外部存儲(chǔ)文件做讀寫(xiě)操作,那么這個(gè)文件就存在了榆鼠。這時(shí)候神妹,應(yīng)用更新题翻,新版本的應(yīng)用是使用targetSdkVersion設(shè)置29的,安裝應(yīng)用(無(wú)論覆蓋安裝還是卸載安裝),此時(shí)依舊能使用舊的方式讀寫(xiě)外部存儲(chǔ)嵌赠,即便手動(dòng)去文件管理器刪除你外部存儲(chǔ)的文件,依舊能正常讀寫(xiě)熄赡。
那么返過(guò)來(lái)姜挺,還是上邊的栗子,在安裝新的應(yīng)用之前彼硫,將舊的應(yīng)用卸載炊豪,并且手動(dòng)去文件管理器刪除你外部存儲(chǔ)的文件,意思就是安裝前清空掉所有拧篮,安裝之后词渤,如果使用Environment.getExternalStorageDirectory()對(duì)外部存儲(chǔ)文件做讀寫(xiě)操作,會(huì)報(bào)錯(cuò)串绩。

4. 設(shè)置requestLegacyExternalStorage屬性

在Manifest中設(shè)置requestLegacyExternalStorage = false能夠關(guān)閉不使用分區(qū)存儲(chǔ)缺虐,也就是說(shuō)設(shè)置這個(gè)屬性之后,你依舊能像以前一樣正常的讀寫(xiě)外部存儲(chǔ)的數(shù)據(jù)礁凡。
這個(gè)方法也是很多人會(huì)去使用的一個(gè)方法高氮,我剛開(kāi)始的時(shí)候也是使用這個(gè)方法,一條代碼能解決問(wèn)題的操作顷牌,它不香嗎剪芍,但是這個(gè)方式也會(huì)存在問(wèn)題,下面會(huì)說(shuō)窟蓝。

5. 根據(jù)官網(wǎng)的要求罪裹,執(zhí)行分區(qū)存儲(chǔ)

其實(shí)也有很多博主也寫(xiě)過(guò)關(guān)于這個(gè)方面的內(nèi)容,無(wú)外乎是兩種方式运挫,使用MediaStore或存儲(chǔ)訪問(wèn)框架(SAF)
按照之前我們讀寫(xiě)外部公共存儲(chǔ)文件的操作一般是這樣寫(xiě)的

String path = Environment.getExternalStorageDirectory()
String name = "TestFN"
File file = new File(path, name);
// todo 然后執(zhí)行IO流讀寫(xiě)

然后如果使用MediaStore的話状共,舉個(gè)栗子的吧,就弄一個(gè)寫(xiě)文件的Demo滑臊,因?yàn)榫W(wǎng)上很多都是圖片視頻什么的口芍,假如寫(xiě)到Downloads文件夾里

ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, "FILENAME");
 //設(shè)置文件類(lèi)型(有哪些類(lèi)型網(wǎng)上很容易查到,如果不設(shè)置的話雇卷,就是默認(rèn)沒(méi)有擴(kuò)展名的文件)
values.put(MediaStore.Downloads.MIME_TYPE, "text/plain");
 //這個(gè)方法只可在Android10的手機(jī)上執(zhí)行鬓椭,設(shè)置路徑
values.put(MediaStore .Downloads.RELATIVE_PATH, "Download/mypath");
Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
// 寫(xiě)入文件
Uri insertUri = resolver.insert(external, values);

// io寫(xiě)入
            OutputStream os = null;
            String test = "aaaaaaaaaa";
            try {
                os = resolver.openOutputStream(insertUri);
                if(os == null){
                    return;
                }
                byte[] buffer = test.getBytes();
                os.write(buffer, 0, buffer.length);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    if (os != null) {
                        os.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

之后可以打開(kāi)文件管理器,在Download文件夾下mypath文件夾下能找到FILENAME.txt文件关划,打開(kāi)能看到里面的內(nèi)容aaaaaaaaaa小染。
使用SAF的話就更加簡(jiǎn)單了

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, code);

然后在onActivityResult中可以獲取到uri,再執(zhí)行讀寫(xiě)操作贮折。

二. 分區(qū)存儲(chǔ)分析

按照谷歌的意思裤翩,大概意思是執(zhí)行分區(qū)存儲(chǔ)是為了能夠更好的管理文件,以前的方式太亂了。
站在用戶的角度去思考踊赠,確實(shí)是這個(gè)改變會(huì)很舒服呵扛,很多流氓軟件卸載之后會(huì)殘留文件在SD卡里面繼續(xù)占內(nèi)存,我去刪的話還要一個(gè)一個(gè)刪除筐带,現(xiàn)在方便了今穿,比如我之前裝了10個(gè)流氓軟件,現(xiàn)在我直接把DownLoad文件夾刪除伦籍,這個(gè)文件夾下的10個(gè)流氓軟件的東西都會(huì)全部刪除蓝晒。
但是站在開(kāi)發(fā)者角度就有點(diǎn)難受了,因?yàn)橐m配Android11帖鸦,到時(shí)候要做數(shù)據(jù)遷移芝薇,莫名其妙的增加了工作量。

然后關(guān)于上面提出的兩個(gè)方案作儿,對(duì)于非媒體文件來(lái)說(shuō)洛二,比如說(shuō)txt這些,我個(gè)人是打算使用MediaStore來(lái)存數(shù)據(jù)立倍,但是我看很多人說(shuō)這些文件最后用SAF灭红,其實(shí)這里我有一個(gè)疑問(wèn),SAF會(huì)打開(kāi)彈框和用戶進(jìn)行交互口注,但并不是所有的需求都是想彈一個(gè)頁(yè)面和用戶交互的吧变擒?比如我捕獲到了異常寫(xiě)到一個(gè)txt文件,想存到外部存儲(chǔ)中寝志,難道我還要彈出一個(gè)彈框問(wèn)用戶這個(gè)異常文件要存到哪嗎娇斑?

三. Android11分區(qū)存儲(chǔ)分析

寫(xiě)這篇文章的這個(gè)時(shí)間點(diǎn),Android11還沒(méi)出


但是存在預(yù)覽版材部,因?yàn)闆](méi)有Google Pixel 4/4 XL毫缆、Pixel 3a/3a XL、Pixel 3/3 XL 和 Pixel 2/2 XL這些機(jī)型進(jìn)行測(cè)試(不想使用模擬器)乐导,那具體的情況估計(jì)等出了之后才知道苦丁,這里就只能做一些簡(jiǎn)單的分析。
個(gè)人覺(jué)得比較靠譜的兩個(gè)消息渠道來(lái)源:
(1)官方的文檔物臂,中文的https://developer.android.google.cn/preview/privacy/storage#scoped-storage
(2)B站的這個(gè)視頻 https://www.bilibili.com/video/BV1fT4y1g74Z
它們大致說(shuō)的內(nèi)容都一樣旺拉,這里拿官方文檔簡(jiǎn)單分析下。

Android11提出強(qiáng)制執(zhí)行分區(qū)存儲(chǔ)棵磷,在Android10中是非強(qiáng)制的蛾狗,上面說(shuō)了,在Manifest中配置requestLegacyExternalStorage屬性可以關(guān)閉分區(qū)存儲(chǔ)仪媒。按這Android11文檔的意思沉桌,是不是在Android11的手機(jī)上即便配置requestLegacyExternalStorage屬性也沒(méi)效,所以上面說(shuō)了再Android10中使用requestLegacyExternalStorage來(lái)規(guī)避分區(qū)儲(chǔ)存的操作,是不可靠的留凭,雖然一行代碼能解決問(wèn)題很香佃扼,但還是建議盡快換種方式。

文檔說(shuō)“在大多數(shù)情況下冰抢,您可以將數(shù)據(jù)遷移到您的應(yīng)用專(zhuān)用目錄松嘶。”挎扰,專(zhuān)用目錄就是context.getExternalFilesDir(),卸載之后也會(huì)刪除巢音,這里還提出了一個(gè)Android11的新屬性 preserveLegacyExternalStorage遵倦,設(shè)置為true也依舊能使用舊的方式讀寫(xiě)儲(chǔ)存,但是重新安裝應(yīng)用等操作之后官撼,這個(gè)屬性也沒(méi)有用了梧躺,意思是這個(gè)屬性是給開(kāi)發(fā)者用來(lái)做數(shù)據(jù)遷移的,其實(shí)Android10的時(shí)候就應(yīng)該開(kāi)始遷移數(shù)據(jù)去適配分區(qū)存儲(chǔ)了傲绣。為了防止很多人沒(méi)做適配掠哥,都用了requestLegacyExternalStorage暫時(shí)關(guān)閉,谷歌爸爸還是很仁慈的打算再給一次機(jī)會(huì)秃诵。

根據(jù)現(xiàn)在的信息得到的東西還是比較少的续搀,具體的情況只能等到Android11發(fā)布之后才知道,比如說(shuō)手機(jī)是Android11的系統(tǒng)菠净,但是我目標(biāo)版本還是設(shè)置低于29禁舷,這種情況是不是也不需要開(kāi)啟分區(qū)存儲(chǔ)。如果說(shuō)即使目標(biāo)版本低于29的情況毅往,在Android11的手機(jī)上也會(huì)強(qiáng)制開(kāi)啟分區(qū)存儲(chǔ)牵咙,那就是說(shuō)明你一定要去做適配了,趁現(xiàn)在還是Android10的時(shí)候趕緊做適配攀唯,新寫(xiě)的文件就開(kāi)始放到分區(qū)存儲(chǔ)的目錄中洁桌,原本就已經(jīng)存在的文件就做個(gè)遷移。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侯嘀,一起剝皮案震驚了整個(gè)濱河市另凌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌残拐,老刑警劉巖途茫,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異溪食,居然都是意外死亡囊卜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)栅组,“玉大人雀瓢,你說(shuō)我怎么就攤上這事∮竦В” “怎么了刃麸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)司浪。 經(jīng)常有香客問(wèn)我泊业,道長(zhǎng),這世上最難降的妖魔是什么啊易? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任吁伺,我火速辦了婚禮,結(jié)果婚禮上租谈,老公的妹妹穿的比我還像新娘篮奄。我一直安慰自己,他們只是感情好割去,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布窟却。 她就那樣靜靜地躺著,像睡著了一般呻逆。 火紅的嫁衣襯著肌膚如雪夸赫。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天页慷,我揣著相機(jī)與錄音憔足,去河邊找鬼。 笑死酒繁,一個(gè)胖子當(dāng)著我的面吹牛滓彰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播州袒,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼揭绑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了郎哭?” 一聲冷哼從身側(cè)響起他匪,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎夸研,沒(méi)想到半個(gè)月后邦蜜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亥至,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年悼沈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贱迟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡絮供,死狀恐怖衣吠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情壤靶,我是刑警寧澤缚俏,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站贮乳,受9級(jí)特大地震影響忧换,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜向拆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一包雀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亲铡,春花似錦、人聲如沸葡兑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讹堤。三九已至吆鹤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洲守,已是汗流浹背疑务。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梗醇,地道東北人知允。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像叙谨,于是被迫代替她去往敵國(guó)和親温鸽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345