【翻譯】Android 數(shù)據(jù)存儲

之前閑著無聊泻轰,研究了下 Android 存儲方面的知識稀拐,順便翻譯了下官方文檔(雖然有已經(jīng)被翻譯過...)荆隘。這里就算是水一篇博客好了 # ̄▽ ̄#

1.1 應(yīng)用數(shù)據(jù)存儲

Android為你提供了一些用來持久保存應(yīng)用數(shù)據(jù)的選擇针贬。你所選擇的解決方案依賴于你明確的需求棘劣,例如數(shù)據(jù)對于你的應(yīng)用來說是否是私有的山宾,還是能被其他應(yīng)用(以及用戶)所獲取至扰,以及你的數(shù)據(jù)需要多大的存儲空間。
你的數(shù)據(jù)存儲方式為以下幾種:

(1) Shared Preferences 共享偏好

以鍵值對的方式存儲私有的簡單的數(shù)據(jù)

(2) Internal storage 內(nèi)部存儲空間

存儲私有數(shù)據(jù)在設(shè)備的內(nèi)存上

(3) External storage 外部存儲空間

存儲公共數(shù)據(jù)在共享的外部存儲上

(4) SQLite Databases 數(shù)據(jù)庫

存儲結(jié)構(gòu)化數(shù)據(jù)在私有的數(shù)據(jù)庫中

(5) Network Connection網(wǎng)絡(luò)連接

在網(wǎng)絡(luò)上用你自己的網(wǎng)絡(luò)服務(wù)器存儲數(shù)據(jù)
Android為你提供了一種為其它應(yīng)用程序暴露私有數(shù)據(jù)的方式來——使用 content provider . (內(nèi)容共享)资锰。content provider 是一種可選的組件敢课,它為那些受限于你施加限制的應(yīng)用數(shù)據(jù)暴露了讀寫方法。需要更多有關(guān)使用conten providers的信息绷杜,請見content providers文檔

1.1.1 使用共享偏好

SharedPreferences 該類 提供了一種通用的框架允許你去保存和重新獲取持久性的直秆、以鍵值對方式保存的原始數(shù)據(jù)種類。你可以使用SharedPreferences去保存任意的原始數(shù)據(jù):布爾類型鞭盟、單精度浮點數(shù)圾结、整型、長整型齿诉、和字符串類型筝野。這種數(shù)據(jù)會持續(xù)作用在整個用戶會話期間(即使你的應(yīng)用被銷毀了)。
為了在你的應(yīng)用中獲取sharedpreferences 對象粤剧,可以使用下列兩種方法之一:
· getSharePreferences() – 若果你需要獲取多種以文件名區(qū)分的偏好文件歇竟,請使用這種方法〉至担可以用第一個參數(shù)來指定文件焕议。
· getPreferences() – 若果你只需要一個偏好文件在你的Activity中,請使用這種方法馋记。因為這種方法會為你的Activity提供唯一的preferences 文件号坡,而你不需要提供文件名懊烤。
寫入值:
(1) 調(diào)用 edit() 函數(shù)來獲取一個 SharedPreferences.Editor。
(2) 使用諸如putBoolean()和putString()等方法來添加值宽堆。
(3) 使用commit()方法來提交新的值
讀取值腌紧,使用SharePreferences的方法,諸如getBoolean()和getString畜隶。
以下是一個例子壁肋,它在計算器中保存了靜音模式的偏好。

public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";
    @Override
    protected void onCreate(Bundle state){
       super.onCreate(state);
       . . .

       //存儲偏好
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }

    @Override
    protected void onStop(){
       super.onStop();

      // 我們需要一個Editor對象來保存偏好的改變
      // 所有的對象都來自于android.context.Context
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);

      // Commit the edits!
      editor.commit();
    }
}

1.1.2 使用內(nèi)部存儲

你可以直接在你的設(shè)備內(nèi)部存儲中保存文件籽慢。默認情況下浸遗,保存在內(nèi)部存儲中的文件對你的應(yīng)用來說是私有的,其它應(yīng)用不能獲取它們(即使是用戶)箱亿。當用戶卸載你的應(yīng)用時跛锌,這些文件也會被刪除。
在你的內(nèi)部存儲中創(chuàng)建和寫一份私有文件:
(1) 通過文件名和操作模式調(diào)用 openFileOutput()届惋。它將返回一個FileOutPutStream對象髓帽。
(2) 使用Write() 方法,對文件執(zhí)行寫操作
(3) 使用close() 方法關(guān)閉流
舉個例子

String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

MODE_PRIVATE 會創(chuàng)建一個文件(或者取代原有的同名文件)脑豹,并且使它對你的應(yīng)用來說是私有的郑藏。
其它可以使用的模式有:MODE_APPEDN MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE
從內(nèi)部存儲中讀取文件
(1) 調(diào)用 openFileInput() 并傳遞文件名。它將返回一個FileInputStream對象
(2) 使用read()方法讀取字節(jié)
(3) 使用close()方法關(guān)閉流
小提示:在應(yīng)用中瘩欺,如果你想在編譯的時候保存一個靜態(tài)的文件必盖,那么請在工程的res/raw/目錄保存它。你可以調(diào)用openRawResource()方法來打開它俱饿,通過傳遞R.raw.<Filename>的id歌粥,這個方法返回一個InputStream對象,你可以用它來讀取文件(但是你不能用他來寫入原始文件)
? 存儲緩存文件
如果你想要臨時存儲一些數(shù)據(jù)稍途,而不是永久性的存儲它阁吝。你應(yīng)該使用getCacheDir()方法去打開一個文件。這個文件代表一個內(nèi)部存儲路徑械拍,在這你可以存儲臨時的緩存文件突勇。
當設(shè)備的內(nèi)部存儲空間較低時,Android系統(tǒng)可能會刪除這些緩存文件來恢復(fù)空間坷虑。然而甲馋,你不應(yīng)該依賴于你的系統(tǒng)去為你清理這些文件。你應(yīng)該始終自己去維持這些緩存文件迄损,并且控制它的空間消耗在一個合理的范圍內(nèi)定躏,例如1MB。當用戶卸載你的應(yīng)用時,這些文件將會被刪除痊远。
? 其它有用的方法
getFilesDir()
獲取在文件系統(tǒng)中垮抗,你內(nèi)部文件保存的絕對路徑。
getDir()
在你內(nèi)部存儲空間中創(chuàng)建(如果存在則打開)路徑碧聪。
deleteFile()
刪除內(nèi)部存儲中的文件冒版。
fileList();
以數(shù)組的方式返回你應(yīng)用中存儲的文件列表。

1.1.3使用外部存儲

任何兼容Android的設(shè)備都支持一個共享的外部存儲逞姿,你可以在這里存儲文件辞嗡。外部存儲可以是一種可移除的存儲媒體(例如 SD card)或者內(nèi)部的(不可移除的)儲存。當用戶接通了USB大容量存儲設(shè)備在電腦上傳輸文件時滞造,保存在外部存儲上的文件時世界可讀的(world-readable)并且可以被用戶修改续室。
注意:外部存儲可能會變成不可獲得的狀態(tài),如果用戶將外部存儲連接到電腦上谒养,或者用戶移除了媒體挺狰。并且,由于沒有一種作用于文件的強制安全措施买窟,所用的應(yīng)用都可以讀或者寫那些存放在外部存儲的文件她渴,用戶也可以刪除它們。
? 獲得對外部存儲的訪問
為了讀寫外部存儲上的文件蔑祟,你的應(yīng)用必須獲取READ_EXTERNAL_STORAGE 或者 WRITE_EXTERNAL_STORAGE 兩個系統(tǒng)權(quán)限。舉個例子:

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

如果你需要同時獲得讀和寫文件的權(quán)限沉唠,那么你只需要請求WRITE_EXTERNAL_STORAGE 權(quán)限疆虚。因為它也間接的請求了讀的權(quán)限。
提示:從android 4.4開始满葛,這些權(quán)限并不是必須的如果你只是去讀寫你應(yīng)用的私有文件径簿。想要知道更多信息,可以查看以下章節(jié)關(guān)于 存儲應(yīng)用私用的文件嘀韧。
? 查看媒介是否可獲得
在你做任何有關(guān)外部存儲的工作之前篇亭,你應(yīng)該總是先調(diào)用getExternalStorageState()方法來檢查媒介是否可獲得。媒介可能連接到了電腦锄贷,未找到译蒂,只讀,或者處于其它狀態(tài)谊却。例如柔昼,你可以使用以下一堆代碼檢查外部存儲的狀態(tài)。
/* 檢查外部存儲是否可獲得以用來進行讀和寫操作*/

public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}
/* 檢查外部存儲是否可獲得并至少能進行讀操作*/
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

這個例子檢查了外部存儲設(shè)備是否可獲得以便去進行讀寫操作炎辨。getExternalStorageState()方法返回了一些你可能想要檢查的其它狀態(tài)捕透。例如,媒介是否能被共享(連接到電腦),是否完全未找到乙嘀,還是已經(jīng)被永久的移除末购,等等。當你的應(yīng)用需要連接到媒體的時候虎谢,你可以使用這些狀態(tài)以告知用戶更多的信息盟榴。
? 存儲可以被其它應(yīng)用共享的文件
通常來講,用戶可能會通過你的應(yīng)用獲得新的文件嘉冒,這些文件應(yīng)該被保存在設(shè)備上的公有空間中曹货。這樣其它應(yīng)用就能獲取它們,并且用戶也能很容易拷貝這些文件讳推。當你這樣做時顶籽,你應(yīng)該使用其中一種共享空間的路徑,例如 Music/银觅,Pictures/礼饱,and Rintones/
為了獲得一個代表合適的公有路徑的File對象,調(diào)用getExternalStoragePublicDirectory()方法究驴,并傳遞一個你想要的路徑類型镊绪,例如DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES,或其它洒忧。通過合理的存放你的文件在對應(yīng)的媒體種類路徑下蝴韭,系統(tǒng)的媒體掃描器就能合理的在系統(tǒng)中分類你的文件(例如,鈴聲會在系統(tǒng)設(shè)置中以鈴聲出現(xiàn)熙侍,而不是音樂)榄鉴。
舉個例子,以下是一種在公有相冊路徑下蛉抓,為新的相冊創(chuàng)建路徑發(fā)方法庆尘。

public File getAlbumStorageDir(String albumName) {
    // 獲取用戶公有的相冊路徑
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

? 存儲應(yīng)用私有的文件
如果你正在處理一些不打算被其他應(yīng)用使用的文件(例如,只會被你的應(yīng)用使用的圖像紋理或者音效)巷送,你應(yīng)該使用getExternalFilesDir()在外部存儲上創(chuàng)建一個私有存儲路徑驶忌。這個方法也需要一個類型參數(shù)來指明子路徑的類型(例如 DIRECTORY_MOVIES),如果不需要一個明確的媒體路徑笑跛,傳值null來獲得你應(yīng)用私有路徑的根路徑付魔。
從Android4.4開始,讀寫應(yīng)用私有路徑中的文件不再需要 READ_EXTERNAL_STORAGE 或者WRITE_EXTERNAL_STORAGE 兩個權(quán)限飞蹂。所以這兩個權(quán)限只有在maxSdkVersion的版本低于18時抒抬,才需要被聲明。

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                     android:maxSdkVersion="18" />
    ...
</manifest>

注意:當用戶卸載了你的應(yīng)用時晤柄,這個路徑及其中的內(nèi)容都會被刪除擦剑。系統(tǒng)媒體掃描器也不會去讀取這些路徑下的文件。所以這些文件在meiaStore的content provider中是獲取不到的。同理惠勒,你也不應(yīng)該在這些路徑存下存放那些本質(zhì)上屬于用戶的媒體赚抡,例如通過你的應(yīng)用捕獲或處理過的照片,或者用戶通過你的應(yīng)用購買的歌曲纠屋,這些文件看起來本應(yīng)該被保存在共享路徑中的文件涂臣。
有時候,設(shè)備可能會分配一部分內(nèi)部存儲作為外部存儲售担,當然也可能會提供SD卡的卡槽赁遗。當這種設(shè)備運行在Android4.3或者更低的版本上時,getExternalFilesDir()方法只會提供一本分內(nèi)部存儲的使用權(quán)族铆,你的應(yīng)用并不能讀寫SD卡上的文件岩四。然而,從Android 4.4開始哥攘,通過getExternalFilesDirs()方法剖煌,你即可以獲得外部存儲的使用權(quán),也可以獲得內(nèi)部存儲的使用權(quán)逝淹。它返回一個File對象的數(shù)組耕姊,該數(shù)組包含每一個位置的入口路徑。數(shù)組中所包含的第一個入口路徑栅葡,被認為是主要的外部存儲茉兰,并且你應(yīng)當使用這一場所,除非它已經(jīng)被占滿或者是不可獲得的欣簇。如果你想要在Android4.3或以下版本獲得兩者的路徑邦邦,可以使用支持包中的靜態(tài)方法。ContextCompat.getExternalFilesDirs(). 這個方法也返回了一個File對象的數(shù)組醉蚁,但在Android4.3或以下的版本上,它通常只包含一個入口鬼店。
注意:盡管getExternalFilesDir()和getExternalFilesDirs()方法提供的路徑并不會被MediaStore的Content provider獲得网棍。但是,其它擁有READ_EXTERNAL_STORAGE權(quán)限的應(yīng)用可以獲得所有外部存儲上的文件妇智,并包含它們滥玷。如果你需要嚴格的限制你的文件的使用權(quán),你應(yīng)該將你的文件寫在內(nèi)部存儲上巍棱。
? 存儲緩存文件
想要打開一個代表著在外部存儲上存放緩存文件的路徑惑畴,你可以調(diào)用getExternalCacheDire()方法,如果用戶卸載你的應(yīng)用航徙,這些文件會自動被刪除如贷。
類似于上述所提到的ContextCompat.getExternalFilesDirs()方法,你同樣可以獲取在第二個外部存儲上的緩存入口(如果可以獲得的話),通過調(diào)用ContextCompat.getExternalCacheDirs()方法杠袱。
小提示:為了保護你的文件存儲空間尚猿,并維持你應(yīng)用的表現(xiàn)。在整個應(yīng)用的生命周期中楣富,細心的管理你的緩存文件凿掂,并在它們不被需要的時候移除它們這些,這是很重要的纹蝴。

1.1.4使用數(shù)據(jù)庫

Android 提供了完整的SQLite數(shù)據(jù)庫的支持庄萎。任何類都能通過數(shù)據(jù)庫名稱來訪問你創(chuàng)建的數(shù)據(jù)庫,但是該應(yīng)用之外的類側(cè)不能塘安。
建議通過繼承SQLiteOpenHelper類來創(chuàng)建新的SQLite數(shù)據(jù)庫糠涛,并重寫其中的onCreate()方法,在該方法中你可以執(zhí)行一條SQLite命令以便在數(shù)據(jù)庫中創(chuàng)建表耙旦。
舉例:

public class DictionaryOpenHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 2;
    private static final String DICTIONARY_TABLE_NAME = "dictionary";
    private static final String DICTIONARY_TABLE_CREATE =
                "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
                KEY_WORD + " TEXT, " +
                KEY_DEFINITION + " TEXT);";
    DictionaryOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DICTIONARY_TABLE_CREATE);
    }
}

然后你可以通過你定義的構(gòu)造器來獲得繼承SQLiteOpenHelper的類的實例脱羡。為了向數(shù)據(jù)庫中寫入和讀出數(shù)據(jù),可以分別調(diào)用getWriteableDatabase()和getReadableDatabase()方法免都。它們都會返回一個SQLiteDatabase對象锉罐,它代表著一個數(shù)據(jù)庫對象并向外提供對SQLite的操作方法。
通過使用SQLiteDatabase query()方法绕娘,你可以對SQLite數(shù)據(jù)庫執(zhí)行查詢操作脓规,它可以接受不同種類的查詢參數(shù),例如表名险领、投影侨舆、選擇運算、列名绢陌、分類以及其它參數(shù)挨下。為了執(zhí)行一些更復(fù)雜的查詢操作,例如那些需要列的別名的操作脐湾,你應(yīng)該使用SQLiteQueryBuilder這個類臭笆,它提供了一些便捷的操作方法來構(gòu)建查詢操作。
每一次SQLite的查詢操作都會返回一個游標秤掌,它指向所有查詢結(jié)果的行愁铺。游標的原理是使你通過它可以駕馭你從數(shù)據(jù)庫中查詢的結(jié)果,并讀取行和列闻鉴。
想獲得一些在Android中演示如何使用SQLite數(shù)據(jù)庫的例子茵乱,可以查看Note Pad和Searchable Ditionary 這些應(yīng)用。
? 數(shù)據(jù)庫調(diào)試
Android SDK 包含了一個 sqlite3 數(shù)據(jù)庫工具孟岛,它允許你瀏覽表的內(nèi)容瓶竭,運行SQL命令督勺,并執(zhí)行其它有用的SQLite數(shù)據(jù)庫操作。查閱Examining sqlite3 databases from a remote shell 來學(xué)習(xí)如何使用該工具在验。

1.1.5使用網(wǎng)絡(luò)連接

你可以使用網(wǎng)絡(luò)(當可獲得時) 在你自己的基于web的服務(wù)上玷氏,來存儲并重新獲取數(shù)據(jù),為了獲得更多的聯(lián)網(wǎng)操作腋舌,你可以使用以下包中的類:
java.net
Android.net

1.2應(yīng)用安裝路徑

從API版本8開始盏触,你可以允許你的應(yīng)用安裝在外部存儲上(例如,設(shè)備的SD卡)块饺。這是一個可選項赞辩,你可以在Mainfest文件中用 android:installLocation 參數(shù)來聲明它。如果你沒有聲明這個元素授艰,你的應(yīng)用只會被裝在內(nèi)部存儲上辨嗽,并且不能被移動到外部存儲中。
為了允許系統(tǒng)在外部存儲上安裝你的應(yīng)用淮腾,修改mainfest文件糟需,在其中包含android:installLocation參數(shù),可以使用的值有preferExternal 或者 auto
舉例:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:installLocation="preferExternal"
    ... >

如果你聲明的參數(shù)的值是preferExternal 谷朝,則你要求你的應(yīng)用裝載在外存儲上 洲押。但是系統(tǒng)并不保證你的應(yīng)用會被安裝在外部存儲上。如果外部存儲已經(jīng)滿了圆凰,系統(tǒng)會安裝在內(nèi)部存儲上杈帐。用戶可以在外部存儲和內(nèi)部存儲之間轉(zhuǎn)移你的應(yīng)用。
如果你聲明的參數(shù)是 auto专钉,則你暗示你的應(yīng)用可能會被安裝在外部存儲上挑童,但你對安裝的位置并沒有指明。系統(tǒng)會基于一些因素來決定在什么位置安裝你的應(yīng)用跃须。用戶同樣也可以在外部存儲和內(nèi)部存儲之間轉(zhuǎn)移你的應(yīng)用站叼。
當你的應(yīng)用被安裝在外部存儲上時:
(1) 只要外部存儲處于連接狀態(tài),對于應(yīng)用的表現(xiàn)就沒有任何影響菇民。
(2) .apk文件會被保存在外部存儲上尽楔,但是用戶所有的私有數(shù)據(jù),數(shù)據(jù)庫玉雾,優(yōu)化后的.dex文件以及提取的本地代碼都會被保存在內(nèi)部存儲上。
(3) 唯一的用來存儲你應(yīng)用的容器已經(jīng)被一個隨機產(chǎn)生的密鑰加密過轻要。這個密鑰只會被最初安裝它的設(shè)備所加密复旬。因此,一個被安裝在外部存儲上的應(yīng)用只會為一臺設(shè)備工作冲泥。
(4) 用戶可以通過系統(tǒng)設(shè)置將你的應(yīng)用移動到內(nèi)部存儲上驹碍。
警告:當用戶通過USB大容量存儲設(shè)備與你的電腦共享文件或者通過系統(tǒng)設(shè)置移除了你的SD卡壁涎,使得外部存儲對于你的設(shè)備來說變得不可獲得,那么被安裝在外部存儲上的應(yīng)用都會立即被結(jié)束掉志秃。

1.2.1向后兼容性

讓應(yīng)用安裝在外部存儲上的這一特征怔球,只有設(shè)備運行的api版本在8(Android的版本2.2)或以上才有用。那些基于api版本8構(gòu)建的應(yīng)用總是會被安裝在內(nèi)部存儲上浮还,并且不能被轉(zhuǎn)移到外部存儲上(即使設(shè)備的api版本為8)竟坛,然而當你的應(yīng)用是為api版本8或以下的版本來設(shè)計的時候,你可以選擇是否支持api版本為8或者以上的版本钧舌,并通過使用api版本8或者更低來編譯担汤。
為了讓應(yīng)用安裝在外部存儲上,并對低于api 8 的版本保持兼容洼冻,你需要:
(1) 在<mainifest>元素中崭歧,包含 android:installLocation參數(shù),使用”auto”或”preferExternal” 兩個值之一撞牢。
(2) 使你的 android:minSdkVersion 參數(shù)保持在低于api 8的版本率碾,并確保你應(yīng)用中的代碼只使用了那些兼容該版本的應(yīng)用程序接口。
(3) 為了編譯你的應(yīng)用屋彪,修改構(gòu)建目標的api 版本為 8所宰。這是必須的,因為在更早的Android庫中不明白 android:installLocation 這個參數(shù)撼班,當它出現(xiàn)時歧匈,也不會去編譯它。
(4) 當你的應(yīng)用被安裝在低于api本版8的設(shè)備上時砰嘁,android:installLocation參數(shù)會被忽略件炉,并且應(yīng)用會被安裝在內(nèi)部存儲上
注意:盡管在更早的版本中,xml中的標記會被忽略矮湘,但當你的minSdkVersion小于8 時你必須小心不要去使用api版本8中的應(yīng)用程序接口斟冕,除非你在你的代碼中做過了必要的向后兼容的工作。

1.2.2不應(yīng)該被安裝在外部存儲上的應(yīng)用

當用戶連接了USB大容量存儲設(shè)備在電腦上共享文件時(或者卸載缅阳、移除了外部存儲)磕蛇,任何正在運行的、安裝在外部存儲上的應(yīng)用都會被結(jié)束掉十办。系統(tǒng)實際上會不知道這些應(yīng)用在哪秀撇,直到大容量存儲設(shè)備被重新安裝到設(shè)備上。除去結(jié)束掉應(yīng)用向族,使應(yīng)用不能被用戶獲得的后果之外呵燕,這種做法也會使得某些種類的應(yīng)用發(fā)生嚴重的錯誤。為了讓你的應(yīng)用一直表現(xiàn)的如你預(yù)期那樣件相,如果它使用了以下的特征再扭,你不應(yīng)該允許你的應(yīng)用被安裝在外部存儲上氧苍。當外部存儲未被裝載時,可能會出現(xiàn)以下結(jié)果:

服務(wù):

你正在運行的服務(wù)會被結(jié)束掉泛范,即使外部存儲被重新裝載時也不會重新運行让虐。但是,你依然可以注冊ACTION_EXTERNAL_APPLICATIONS_AVAILABLE的事件廣播罢荡。當被安裝在外部存儲上的應(yīng)用對系統(tǒng)來說變得可獲得時赡突,這個廣播會通知你的應(yīng)用,此時你可以重啟你的服務(wù)柠傍。

鬧鐘服務(wù):

你的通過AlarmManager注冊的鬧鈴會被取消麸俘,你必須手動再次注冊鬧鐘服務(wù),當外部存儲被重新裝載時惧笛。

輸入法引擎:

你的輸入法引擎會被默認的取代从媚。當你的外部存儲被重新裝載時,用戶可以打開系統(tǒng)設(shè)置重新使用你的輸入法引擎患整。

動態(tài)壁紙:

你正在運行的動態(tài)壁紙會被默認的動態(tài)壁紙所代替拜效。當外部存儲被重新裝載時,用戶可以重新選擇你的動態(tài)壁紙各谚。

應(yīng)用組件:

你的應(yīng)用組件會從主界面移除紧憾。當外部存儲重新裝載時,你的應(yīng)用組件對于用戶來說是不可選取的昌渤,直到系統(tǒng)重置主界面應(yīng)用(通常直到系統(tǒng)重啟赴穗,都不會這樣)

賬戶管理:

你通過AccountManager創(chuàng)建的用戶會消失,直到外部存儲重新裝載膀息。

異步適配:

你的AbstractThreadedSyncAdapter和其它異步方法都會停止工作般眉,直到外部存儲重新裝載。

設(shè)備管理者:

你的DeviceAdminReceiver及其所有管理功能都會不能使用潜支,這可能會給設(shè)備功能造成不可預(yù)見的后果甸赃,即便外部存儲重新裝載后,這個問題也會持續(xù)冗酿。

監(jiān)聽啟動完成的廣播接收者:

在外部存儲被裝載之前埠对,系統(tǒng)會發(fā)送ACTION_BOOT_COMPLETED的廣播。如果你的應(yīng)用安裝在外部存儲上裁替,你永遠也接受不到這個廣播项玛。

如果你的應(yīng)用使用了任何以上列出的特征,你應(yīng)該允許你的應(yīng)用被安裝在外部存儲上弱判。默認情況下襟沮,系統(tǒng)也不會允許你的應(yīng)用安裝在外部存儲上,所以你也不需要擔(dān)心那些已經(jīng)存在的應(yīng)用。然而臣嚣,如果你的確信你的應(yīng)用永遠也不應(yīng)該被安裝在外部存儲上,那么你可以通過聲明android:installLoaction的值為”internalOnly”剥哑。盡管這并不會改變默認行為硅则,但這個聲明明確的指出了你的應(yīng)用應(yīng)該被安裝在內(nèi)部存儲上,并作為一個提醒告知其它開發(fā)者株婴。

1.2.3應(yīng)該被安裝在外部存儲上的應(yīng)用

簡而言之怎虫,任何沒有使用到上述特征的應(yīng)用安裝在外部存儲上時,都是安全的困介。大型游戲一般都是應(yīng)該被安裝在外部存儲上的應(yīng)用類型大审,因為當游戲閑置時,不需要額外的服務(wù)座哩。當外部存儲變得不可獲得時徒扶,游戲進程會被結(jié)束掉。當外部存儲重新可獲得根穷,用戶重啟了游戲時(假設(shè)游戲在整個活動周期中合理的保存了它的狀態(tài)) 也不會有任何可見的影響姜骡。
如果你的應(yīng)用需要一些兆字節(jié)的文件,你應(yīng)該仔細考慮是否應(yīng)該將應(yīng)用安裝在外部存儲上屿良,以便讓用戶更好的保護內(nèi)部存儲上的空間圈澈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尘惧,隨后出現(xiàn)的幾起案子康栈,更是在濱河造成了極大的恐慌,老刑警劉巖喷橙,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啥么,死亡現(xiàn)場離奇詭異,居然都是意外死亡重慢,警方通過查閱死者的電腦和手機饥臂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來似踱,“玉大人隅熙,你說我怎么就攤上這事『搜浚” “怎么了囚戚?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長轧简。 經(jīng)常有香客問我驰坊,道長,這世上最難降的妖魔是什么哮独? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任拳芙,我火速辦了婚禮察藐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舟扎。我一直安慰自己分飞,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布睹限。 她就那樣靜靜地躺著譬猫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪羡疗。 梳的紋絲不亂的頭發(fā)上染服,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音叨恨,去河邊找鬼柳刮。 笑死,一個胖子當著我的面吹牛痒钝,可吹牛的內(nèi)容都是我干的诚亚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼午乓,長吁一口氣:“原來是場噩夢啊……” “哼站宗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起益愈,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤梢灭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蒸其,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敏释,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年摸袁,在試婚紗的時候發(fā)現(xiàn)自己被綠了钥顽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡靠汁,死狀恐怖蜂大,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝶怔,我是刑警寧澤奶浦,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站踢星,受9級特大地震影響澳叉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一成洗、第九天 我趴在偏房一處隱蔽的房頂上張望五督。 院中可真熱鬧,春花似錦瓶殃、人聲如沸概荷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至继薛,卻和暖如春修壕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背遏考。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工慈鸠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灌具。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓青团,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咖楣。 傳聞我的和親對象是個殘疾皇子督笆,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容