Context.getDir

  1. Context context ;  
  2. private final String APP_CONFIG ="config";  
  3. File dirConf= context.getDir(APP_CONFIG, Context.MODE_PRIVATE);  
  4. File conf = new File(dirConf, APP_CONFIG);  

則配置文件的路徑爲:data/data/包名/app_+APP_CONFIG /APP_CONFIG ,其中包名後面的app_是爲調用時,系統自己加上的、


Android實戰技巧:數據存儲方式

無論是神馬平臺,神馬開發環境,神馬軟件程序,數據都是核心。對於開發平臺來講,如果對數據的存儲有良好的支持,那麼對應用程序的開發將會有很大的促進作用。

 

總體的來講,數據存儲方式有三種:一個是文件,一個是數據庫,另一個則是網絡。其中文件和數據庫可能用的稍多一些,文件用起來較爲方便,程序可以自己定義格式;數據庫用起稍煩鎖一些,但它有它的優點,比如在海量數據時性能優越,有查詢功能,可以加密,可以加鎖,可以跨應用,跨平臺等等;網絡,則用於比較重要的事情,比如科研,勘探,航空等實時採集到的數據需要馬上通過網絡傳輸到數據處理中心進行存儲並進行處理。

 

對於Android平臺來講,它的存儲方式也不外乎這幾種,按方式總體來分,也是文件,數據庫和網絡。但從開發者的角度來講它可以分爲以下五種方式:

 

SharedPreferences共享偏好

Internal Storage內部存儲空間

External Storage外部存儲空間

SQLite Database數據庫

Internet網絡

這幾種方式各自有各自的優點和缺點,要根據不同的實際情況來選擇,而無法給出統一的標準。下面就各種方式談談它們的優缺點,以及最合適的使用情況:

Shared Preferences共享偏好

SharedPreferences是用來存儲一些Key/Value類似的成對的基本數據類型,注意,它只能存儲基本數據類型,也即int, long, boolean, String, float。事實上它完全相當於一個HashMap,唯一不同的就是HashMap中的Value可以是任何對象,而SharedPreferences中的值只能存儲基本數據類型(primitive types)。

對於它的使用方法,可以參考Android Developer Guide,這裏不重複。

 

如此來看,最適合SharedPreferences的地方就是保存配置信息,因爲很多配置信息都是Key/Value。事實上,在Android當中SharedPreferences使用最多的地方也是用來保存配置(Settings)信息,系統中的Settings中這樣,各個應用中的Settings也是這樣。並且,Android中爲了方便的使用SharedPreferences保存配置信息,它來專門有PreferenceActivity用來封裝。也就是說如果你想在應用程序中創建配置(Settings),你可以直接使用PreferenceActivity和一些相關的專門爲Preference封裝的組件,而不用再直接去創建,讀取和保存SharedPreference,Framework中的這些組件會爲你做這些事。

 

再談談一些使用SharedPreference時的技巧,它只能保存基本數據類型,但假如我想保存一個數組,怎麼辦?可以把數據進行處理,把它轉化成一個String,取出的時候再還原就好了;再如,如想保存一個對象,怎麼辦,同樣,可以把對象序列化成爲字符序列,或轉成String(Object.toString()),或是把它的HashCode(Object.hashCode())當成Value保存進去。

 

總之,SharedPreferences使用起來十分的方便,可以靈活應用,因爲它簡單方便,所以能用它就儘量不要用文件或是數據庫。

 

Internal Storage內部存儲空間

所謂的內部存儲與外部存儲,是指是否是手機內置。手機內置的存儲空間,稱爲內部存儲,它是手機一旦出廠就無法改變,它也是手機的硬件指標之一,通常來講手機內置存儲空間越大意味着手機價格會越貴(很多地方把它稱爲手機內存,但我們做軟件的知道,這並不準確,內存是指手機運行時存儲程序,數據和指令的地方;這裏應該是手機內部存儲的簡稱爲內存,而並非嚴格意義上的內存)。

 

內部存儲空間十分有限,因而顯得可貴,所以我們要儘可能避免使用;另外,它也是系統本身和系統應用程序主要的數據存儲所在地,一旦內部存儲空間耗盡,手機也就無法使用了。所以對於內部存儲空間,我們要儘量避免使用。上面所談到的Shared Preferences和下面要談到的SQLite數據庫也都是存儲在內部存儲空間上的。

 

Android本身來講是一個Linux操作系統,所以它的內部存儲空間,對於應用程序和用戶來講就是“/data/data"目錄。它與其他的(外部的存儲)相比有着比較穩定,存儲方便,操作簡單,更加安全(因爲可以控制訪問權限)等優點。而它唯一的缺點就是它比較有限,比較可貴。

 

雖然,可以非常容易的知道程序本身的數據所在路徑,所有的應用程序的數據路徑都是“/data/data/app-package-name/”,所有的程序用到的數據,比如libs庫,SharedPreferences都是存放在這個路徑下面。但我們在使用的時候最好不要,或是千萬不要直接引用這個路徑。

 

使用內部存儲主要有二個方式,一個是文件操作,一個是文件夾操作。無論哪種方式,Context中都提供了相應的函數來支持,使用Context不但操作簡單方便,最重要的是Context會幫助我們管理這些文件,也可以方便幫助我們控制文件的訪問權限。先來系統的說下Context中關於文件和文件夾操作的函數有哪些。

 

       a. 創建一個文件,並打開成一個文件輸出流,需要提供一個String,作爲文件名

 

print?

FileOutputStream  output = Context.openOutputFile(filename,Context.MODE_PRIVATE); 

output.write(data);// use output to write whatever you like 

output.close(); 

       b.  同樣,想打開一個文件作爲輸入的話,也是只需要提供文件名

 

print?

FileInputStream input = Context.openInputFile(filename); 

input.read(); 

input.close();  

       c.  列出所有的已創建的文件

print?

String[] files = Context.fileList(); 

for (String file : files) { 

    Log.e(TAG, "file is " + file); 

      d.  刪除文件,能創建就要能夠刪除,當然也會提供了刪除文件的接口,它也非常簡單,只需要提供文件名

 

print?

if (Context.deleteFile(filename)) { 

   Log.e(TAG, "delete file " + filename + " sucessfully“); 

} else { 

   Log.e(TAG, "failed to delete file " + filename); 

      e.  獲取文件已創建文件的路徑,它返回一個文件對象用於操作路徑

 

 

print?

File fileDir = Context.getFileDir(); 

Log.e(TAG, "fileDir " + fileDir.getAbsolutePath(); 

      f.  創建一個目錄,需要傳入目錄名稱,它返回 一個文件對象用到操作路徑

print?

File workDir = Context.getDir(dirName, Context.MODE_PRIVATE); 

Log.e(TAG, "workdir " + workDir.getAbsolutePath(); 

       g. 以File對象方式查看所創建文件,需要傳入文件名,會返回文件對象

 

print?

File store = Context.openFileStreamPath(filename); 

Log.e(TAG, "store " + store.length()); 

      h. 獲取Cache路徑,無需要傳入參數,返回文件對象

 

print?

File cachedir = Context.getCacheDir(); 

Log.e(TAG, "cachedir " + cacheDir.getAbsolutePath()); 

總結一下文件相關操作,可以得出以下三個特點:

      1. 文件操作只需要向函數提供文件名,所以程序自己只需要維護文件名即可;

      2. 不用自己去創建文件對象和輸入、輸出流,提供文件名就可以返回File對象或輸入輸出流

 

      3. 對於路徑操作返回的都是文件對象。

 

如前所述,內部存儲空間有限,可貴,安全,穩定,所以應該用來保存比較重要的數據,比如用戶信息資料,口令祕碼等不需要與其他應用程序共享的數據。也可以用來創建臨時文件,但一定要注意及時刪除。另外,對於內部存儲還有一個非常重要的特點,那就是在應用程序被卸載時,應用程序在內部存儲空間的文件數據將全部被刪除。系統這樣做的原因很簡單,就是因爲內部存儲很有限,它必須保證它的可用性,因爲一旦添滿,系統將無法再正常工作。

 

External Storage外部存儲空間

再來談談手機外部存儲空間,與內部存儲空間相對,外部存儲空間是指手機出廠的時候不存在,用戶在使用時候可以自由添加的外部存儲介質比如TS卡,SD卡等閃存儲介質。這些閃存介質由最初的空間小价格貴,到現在的大容量價格便宜,所以幾乎每個支持外部存儲的手機上面都有大容量(大於等於2G)的閃存卡。

 

Android也是不例外,它完全支持外部存儲介質。其實更確切的說,它是要依賴於外部存儲卡的,因爲對於Android系統,如果沒有外部存儲卡,很多的系統應用無法使用,比如多媒體相關的應用程序無法使用。雖然Android很依賴,但是外部存儲卡也有它自身的特點,它最大的優點就是存儲空間大,基本上你可無限制的使用,也不怎麼擔心去清除數據。就目前來看,很多程序都在使用外部存儲卡,但很少有程序去主動清理數據,所以無論你的SD卡有多大,它的可用空間卻越來越少。與內部存儲不同的是,當程序卸載時,它在外部存儲所創建的文件數據是不會被清除的。所以清理外部存儲空間的責任丟給了用戶自己,每隔一段時間就去查看下SD卡,發現無用數據立馬刪除。外部存儲的缺點就是不是很穩定,對於Android手機來講可以說,很不穩定,本身閃存介質就容易出問題,SD卡處於不能正常使用的狀態十分多。

 

先來說說外部存儲相關的使用方法和API:

 

    a. Check media availability檢查介質的可用性

 

        如前所述,外部存儲介質的穩定性十分的差,所以在使用之前一定要先檢查它的可用性,如果可用再去用

 

 

print?

final String state = Environment.getExternalStorageState(); 

if (state.equals(Environment.MEDIA_MOUNTED) || state.equals(Environment.MEDIA_READ_ONLY)) {// sd card is ready to us } 

        b. Get the directory獲取外部存儲卡的路徑

        事實上,外部存儲卡的路徑是“/mnt/sdcard",所以你直接這樣寫去訪問也能訪問的到。鑑於可讀性和可移植性的考慮,建議這樣寫:

 

 

print?

File sdcardDir = Environment.getExternalStorageDirectory(); 

      c. For API 8 or greater, there are some other useful APIs helping to manager files and directories.

         如果你使用API 8(Android 2.2)或者更高,那麼SDK中又多了幾個操作外部存儲文件和路徑的接口,文檔中也建議開始者更加規範的使用SD卡。比如,創建相應的目錄去存儲相應的數據,Music,Picture,Video等。應用程序目錄也變成了"/Android/data/package-name/data"。具體的使用可以參考文檔,這裏不重複。當然,就像編程規範一樣,這裏只是規範,你完全可以不遵守它,但出於可讀性和可移植性,還是建議按照文檔建議的去做。

 

下面總結一下使用時應該注意的一些和外部存儲的特點:

 

     a. 外部存儲卡不是隨時想用就能夠用的,所以一定要記得在使用之前檢查它的可用性

 

     b. 存儲在外部存儲卡上的數據是所有應用程序都可見,用戶也可見(使用FileManager),所以安全性不是很好,雖然文檔聲稱可以在外部存儲卡上寫程序私有數據,但貌似沒用,用FileManager仍然可以刪除或編輯文件(Market上面的FileManager功能都十分的強大,能讓用戶看到SD卡中的所有文件,和操作能看到的文件)。

 

     c. Android手機支持把外部存儲卡Mount至PC做爲U盤,當連接數據線時,這時SD卡變成了U盤連接到了另外的操作系統中。什麼意思,就是在Android當中雖然有的文件屬性(隱藏,私有等),到了PC上就不一定管用了,用戶在PC上可以隨意操作文件(這就是第二點中所提及的)。

 

     d. 如果使用外部存儲卡保存數據,一定要額外做好異常處理:外部存儲卡不可用時把數據存入哪裏;可用的時候再怎麼同步數據(這是比較頭疼的地方,可行的做法就是當SD卡不可用時不準用戶寫數據,但這用戶體驗又不是很好,但如你所知,很多應用都這麼幹);你的數據被破壞了。當然常見的異常也要考慮,比如空間滿了,無法寫入,磁盤壞道等。

 

SQLite Database數據庫

Android對數據庫的支持很好,它本身集成了SQLite數據庫,每個應用都可以方便的使用它,或者更確切的說,Android完全依賴於SQLite數據庫,它所有的系統數據和用到的結構化數據都存儲在數據庫中。

 

它具有以下優點:

 

     a. 效率出衆,這是無可否認的

 

     b. 十分適合存儲結構化數據

 

     c. 方便在不同的Activity,甚至不同的應用之間傳遞數據

 

        先前有一篇文章講到了不同Activity和不同應用之間傳遞數據的麻煩,特別是對於大型數據結構,因爲Activity雖是Java對象,但去無法像使用其他類對象那樣去創建一個實例然後使用它,更無法給Activity加上Setters和Getters(雖然這樣做了沒有編譯錯誤)。比較好的解決方案就是把結構化數據寫入數據庫,然後在不同的Activity之間傳遞它們的Uri。

 

     d. 由專門的ContentProvider來幫忙管理和維護數據庫

 

     e. 可以方便的設置訪問權限,私有還是都可見

 

     f.  操作方便,使用標準的CRUDE語句,ContentResolver.query(), update(), delete() insert(),詳見ContentResolver

 

     g. 良好的可移植性和通用性,用標準的SQL語句就能實現CRUDE

 

對於它的使用方法可以去參考文檔,這裏也說不清楚。

 

Internet網絡

網絡是比較不靠譜的一個,因爲移動終端的網絡穩定性,以及所產生的流量讓人傷不起,用戶更傷不起。但若是對於非常重要的實時數據,或是需要發送給遠端服務器處理的,也可以考慮使用網絡實時發送。這已經有先例了,Apple和Google就是這樣,iPhone設備和Android設備都會在用戶不知情的情況 下收集用戶的信息,然後又在用戶不知情的情況 下發送到Apple和Google的服務器上,也就是所謂的“跟蹤門”。除此之外,智能手機(特別是Android和火熱的iPhone)上面的應用程序都會偷偷的在後臺運行,收集用戶數據,然後再偷偷的發服務器,直接傷害是用戶流量,請看先前的文章。

 

 

 

對比這幾種方式,可以總結下:

 

     1. 簡單數據和配置信息,SharedPreference是首選;

 

     2. 如果SharedPreferences不夠用,那麼就創建一個數據庫

 

     3. 結構化數據,一定要創建數據庫,雖然這稍顯煩鎖,但是好處無窮

 

     4. 文件就是用來存儲文件(也即非配置信息或結構化數據),如文本文件,二進制文件,PC文件,多媒體文件,下載的文件等等。

 

     5. 儘量不要創建文件

 

     6. 如果創建文件,如果是私密文件或是重要文件,就存儲在內部存儲,否則放到外部存儲

 

     7. 不要收集用戶數據,更不要發到網絡上,雖然你們也有很多無奈。用戶也無奈,也無辜,但更無助

 

平臺爲開發者準備了這麼多的方式固然是一件好事,但我們要認清每一種的優點和缺點,根據實際情況選擇最合適的。還有一個原則就是最簡單原則,也就是說能用簡單的方式處理,就不要用複雜的方式。比如存儲幾個數據或簡單對象,用SharedPreference也能做到,何必還去寫個ContentProvider呢?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章