前言,好吧,這部分,沒那么多要說的,其實,就是運用。主要是,畢竟客戶端,存儲并非重點。不過,還是要了解和學習的
先來補充一點基礎嘗試吧:(免得以后,聽到別人聊起,自己一臉蒙蔽)
ADT:Android 開發工具
API:應用程序編程接口
IDE:集成開發環境
JDK:Java 開發工具包
JSON:JavaScript 對象表示法
SDK:軟件開發工具包
SQL:結構化查詢語言
UI:用戶界面
XML:可擴展標記語言
ok,回到正題,本文,主要講的是數據存儲,主要是以系統講解為主,因為,如果只是運用的話,大可百度,一大堆文章可以看,一大堆框架可以用。順便說一下:我寫的自我提升系列,都是屬于系統的介紹某個東西,深入介紹會在后面的其他系列中寫。
原本是打算從一個例子出發的,不過,后來想了一想,這個問題,還是留給讀者自己去想吧,不然,讀者都不會思考了。下面就簡單介紹一下常用的存儲方式吧,這里,將會單純的從技術層面去介紹。
SharedPreferences
這玩意,算是這些存儲中最簡單的方式了吧,不過,還是有一些細節需要知道,不然,也容易出錯的
簡單介紹
SharePreferences是用來存儲一些簡單配置信息的一種機制,使用Map數據結構來存儲數據,以鍵值對的方式存儲,采用了XML格式將數據存儲到設備中,只能在同一個包內使用,不能在不同的包之間使用,其實也就是說只能在創建它的應用中使用,其他應用無法使用。(這里順便說一下,在libary引入的情況下,也是可以使用的,不過,順序是,引用者和自己可以使用,其他不可以使用)
創建的存儲文件保存在/data/data//shares_prefs文件夾下。
創建文件的模式
Context.MODE_PRIVATE(個人建議,用這種模式)
默認操作模式,表示xml存儲文件是私有的,只能在創建文件的應用中訪問(如果其他應用和創建該文件的應用具有相同的uid,也可以直接訪問)。
Context.MODE_WORLD_WREADABLE(不建議使用)
開放讀模式,表示允許其他應用進程具備對該文件的讀權限。官方文檔不建議使用該模式,因為這為導致嚴重的安全漏洞。
Context.MODE_WORLD_WRITABLE(不建議使用)
開放寫模式,表示允許其他應用進程具備堆該文件的寫權限,原因同上一條
Context.MODE_APPEND(個人不建議使用,嫌麻煩)
追加模式,和openFileOutput一起使用。該模式下如果文件存在,就往文件末尾進行追加,否則創建新文件。
簡單使用
通過Context.getSharedPreferences方法獲取SharedPreferences對象,參數分別為存儲的文件名和存儲模式。
?獲取SharedPreferences對象
SharedPreferences?sp?=?getSharedPreferences(DATABASE,?Activity.MODE_PRIVATE);
?獲取Editor對象
Editor?editor?=?sp.edit();
插入數據
調用Editor.putxxxx方法,兩個參數分別為鍵和值。(注意,這里put要指明類型,比如putSting(?,?))
獲取數據:
調用Editor.getxxxx方法,兩個參數分別為鍵和不存在指定鍵時的默認值。
刪除數據:
調用Editor.remove方法,參數為指定的鍵。
清空所有數據:
調用Editor.clear方法
上述所有方法調用都要執行Editor.commit方法來提交,例子:editor.putString("hello",hello).commit.
個人封裝方法(由于,常規的寫法,個人覺得,要去寫key,后面用的時候,也要寫key,感覺很煩,所以就把key集成在了名字里面)
我的包結構吧,名字應該很形象吧。多的就不說,繼續往下看。
這個BaseSp的左右,就是初始化sp,我這里,舉例,就只寫了String的api。其他的是一個意思的。
這里的BasePrefItem是父類item,這其中,簡單的用到了泛型,因為,我并不知道我要存什么類型的key value。
這里是具體的item,當然,是以String為例的,多的不想解釋,代碼很明顯了。
這里是具體的sp了,繼承basesp,寫入文件名,然后,就是創建各個類型的item,一次寫好,一輩子不愁的思想。
使用,簡單吧,經過我前面的封裝,使用,永遠是一句話,而且,看名字就明了了吧,不用再去找一個類,專門放各種常量了吧,這種寫法,唯一比較大的類,就是上面的AppSP這個類了,不過,通常,我會根據業務,或者數據模型,去寫不同的實現類 SP。
需要注意一點:SP是線程不安全的,所以,在同步,多線程里面,最好不要用SP。
SQLite數據庫
這玩意,說實話,我在項目中,用得比較少,講真,在這個時代,網絡才是王道(客戶端而言)。不過,也得學,不是
SQLite 介紹
SQLite 一個非常流行的嵌入式數據庫,它支持 SQL 語言,并且只利用很少的內存就有很好的性能。此外它還是開源的,任何人都可以使用它。許多開源項目((Mozilla, PHP, Python)都使用了 SQLite.
SQLite 由以下幾個組件組成:SQL 編譯器、內核、后端以及附件。SQLite 通過利用虛擬機和虛擬數據庫引擎(VDBE),使調試、修改和擴展 SQLite 的內核變得更加方便。為了解釋,在網上找的簡易版示意圖。
SQLite 基本上符合 SQL-92 標準,和其他的主要 SQL 數據庫沒什么區別。它的優點就是高效,Android 運行時環境包含了完整的 SQLite。
SQLite 和其他數據庫最大的不同就是對數據類型的支持,創建一個表時,可以在 CREATE TABLE 語句中指定某列的數據類型,但是你可以把任何數據類型放入任何列中。當某個值插入數據庫時,SQLite 將檢查它的類型。如果該類型與關聯的列不匹配,則 SQLite 會嘗試將該值轉換成該列的類型。如果不能轉換,則該值將作為其本身具有的類型存儲。比如可以把一個字符串(String)放入 INTEGER 列。SQLite 稱這為“弱類型”(manifest typing.)。
此外,SQLite 不支持一些標準的 SQL 功能,特別是外鍵約束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 還有一些 ALTER TABLE 功能。(這其實也是sqlite的雞肋之處)
除了上述功能外,SQLite 是一個完整的 SQL 系統,擁有完整的觸發器,交易等等。(小但強大)
Android 集成了 SQLite 數據庫
Android 在運行時(run-time)集成了 SQLite,所以每個 Android 應用程序都可以使用 SQLite 數據庫。對于熟悉 SQL 的開發人員來時,在 Android 開發中使用 SQLite 相當簡單。但是,由于 JDBC 會消耗太多的系統資源,所以 JDBC 對于手機這種內存受限設備來說并不合適。因此,Android 提供了一些新的 API 來使用 SQLite 數據庫,Android 開發中,我們需要學使用這些 API。
數據庫存儲在 data/< 項目文件夾 >/databases/ 下。
Android 開發中使用 SQLite 數據庫
關于這個數據庫的問題,個人而言實在是沒多少可以說的,畢竟對sqlite的使用比較少,不想誤導大家,所有,就請大家自行百度,sqlite語法了吧。
不過,先提出幾個理念:數據庫的一行,相當于,java中的一個對象。所以,在Android中,使用sqlite,一般都是,把對象存為一個表,這個表中只有一行最新的唯一數據,而使用的時候,通常也是取出一行,賦值給一個對象,然后,操作對象。
這一部分,算是寫得有點水了吧,不過,沒法。見諒了。順帶說一句,本來,是想好好說一下關于數據庫更新的問題,不過發現,數據更新是個麻煩事兒,特別是涉及到跨版本升級的問題。這里,就不多說了,只是提一句。
Internal Storage 和 External Storage
簡單介紹(Internal Storage 其實就是我們說的私有數據,External Storage簡單說,就是sdcard,簡單可以這么粗暴的理解)
Internal Storage 和 External Storage 的區別
Internal storage 是屬于應用程序的,文件管理器看不見。(私有)
External storage 在文件瀏覽器里是可以看見的? /mnt 。(共有)
這兩個概念都是相對于應用來說的,應該理解為邏輯上的概念,不應理解為物理上的外部SD卡和手機或移動設備內存.。
一個應用把數據存在external storage上時,那么數據成為共有的,所有人都可見的和可用的。
存在internal storage上時,只有這個應用本身可以看到和使用。
很多沒有插SD卡的設備,系統會虛擬出一部分存儲空間用來做公共存儲(主要是音樂,文檔之類的media)。
所以:如果是私密性,安全性的文件數據,就存Internal Storage,如果是大家共用的就存External Storage(ps:在高手面前,這兩個都是可以被查看的,只是相對于軟件本身是安全的,私密的)
Internal Storage 把數據存儲在設備內部存儲器上,存儲在/data/data//files目錄下。
默認情況下在這里存儲的數據為應用程序的私有數據,其它應用程序不能訪問。
卸載應用程序后,內部存儲器的/data/data/目錄及其下子目錄和文件一同被刪除。
ok,下面再詳細,分別介紹,這二者是怎么使用的:
Internal Storage使用介紹
存數據(也可以叫寫數據,其實正規叫法是寫數據,不過,方便理解,就交存數據)
1. 調用openFileOutput(String fileName, int mode)方法,
若fileName對應的文件存在,就打開該文件,若不存在,并以mode權限創建該文件并打開,該方法
返回一個指向fileName對應文件的FileOutputStream,使用這個FileOutputStream可向文件中寫入數據。
2. 調用FileOutputStream對象的write()方法向文件中寫入數據。
3. 調用FileOutputStream對象的close()方法關閉文件寫入流。
例:向內部存儲器中寫入一個名為"abc.txt"的文件后,會在內部存儲器的/data/data//files/目錄下生成"abc.txt"文件。
1,2,3步對應上圖。login就是我們所存的文件,文件中我們存如了username和password。
取數據(也叫讀數據)
1. 調用openFileInputStream(String fileName)方法打開內部存儲器中fileName對應的文件,若該文件存在,該方法
返回一個指向fileName文件的FileInputStream對象。
2. 調用FileInputStream對象的read()方法讀取fileName文件中的內容。
3. 調用FileInputStream對象的close()方法關閉文件讀取流。
如上圖,經過讀取數據之后,會把讀出來的字符放到buffer中,然后,我們就可以從buffer中,拿出我們要的string了。
ok,內部存儲的知識,就介紹到這里,不過,這個內部存儲有一個軟肋,就是軟件被卸載,他就沒有了,這點和sp其實差不多,所以,當我們需要保存一些數據,達到,就算軟件卸載了,再安裝也能使用的效果時,就需要用到接下來要用的東西了,外部存儲。
External Storage 簡單介紹即使用
簡單介紹
它并非始終可用,因為用戶可采用 USB 存儲設備的形式裝載外部存儲,并在某些情況下會從設備中將其移除。
它是全局可讀的,因此此處保存的文件可能不受您控制地被讀取。
當用戶卸載您的應用時,保存在Environment.getExternalStoragePublicDirectory()目錄里的文件不會被刪除,保存在getExternalFilesDir()或getExternalCacheDir()目錄里的文件會被刪除
對于無需訪問限制以及您希望與其他應用共享或允許用戶使用計算機訪問的文件,外部存儲是最佳位置。
如果您的應用需要只需讀取外部存儲,需在清單文件申請android.permission.READ_EXTERNAL_STORAGE權限
如果您的應用需要寫入(隱含讀取)外部存儲,只需在清單文件申請android.permission.WRITE_EXTERNAL_STORAGE權限
通常,是兩個權限都申請
存數據:(寫入)
1? 通過Environment類的getExternalStorageState()方法來判斷手機是否有SDcard:
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
2.獲取SD卡的目錄
File file = Environment.getExternalStorageDirectory();
3.創建文件,或者在原文件中添加數據
FileOutputStream fileW =newFileOutputStream(file.getCanonicalPath() +"/test.txt");
fileW.write(str.getBytes());
4.關流
fileW.close();
細心的同學,應該會注意到,這里的filew.close為什么不是寫在finaly里面呢?好吧,的確應該寫在finaly里面的,或許又有發現,怎么在存數據的最后沒有清空緩存呢?好吧,其實也應該那么做的,所以,最正確的寫法,應該是在寫入數據之后,清空緩存,然后在finaly里面close。
那么,我為什么不這么寫呢?因為我以前就是這么寫的,但是,也沒有出錯。不過,最好還是嚴謹一點吧。
取數據:(讀出)
1.判斷sd卡是否存在,獲取sd卡目錄
2.獲取文件,判斷文件是否存在(這里其實,就是先假設文件存在,獲取文件)
3.打開文件輸入流
4.把讀出來的數據,添加到buffer
5.遍歷buffer,轉換成string
ok,外部存儲,基本就是這樣了。
小結
這一篇文章寫的時間,相對比較長,主要寫得合適,不能太復雜,也不能太簡單。其實,本問中,對于數據的地方,真心想寫,但也不敢寫,這部分,說簡單,也簡單,說難也難。所以,干脆就簡單介紹一下。本文主要介紹了Android本地存儲的一些基本東西,不過,說實在的,就app而言的話,這部分,個人覺得不是特別重要(但是,還是重要的,只是程度沒有網絡,線程,效果那些重要,當然,難度,也相對較低),但是,如果走比較深入的話,那就另當別論了。比如,數據庫的版本更新,數據結構的設計等等。不然怎么有專門的數據庫架構師。