Android SDK上手指南:應用程序數據

版權聲明:本文為博主原創文章,轉載請標明出處。 https://blog.csdn.net/chaoyu168/article/details/52996965

在本系列教程當中,我們將學習如何從零開始進行Android SDK開發。我們已經熟悉了Android應用程序的結構與基本組成元素,其中包括資源、清單與用戶界面。在著手進行Android平臺的功能性應用開發之后,大家肯定需要保存這樣或者那樣的數據信息。Android平臺提供多種選項,用于打理應用程序中的數據存儲任務,而這正是今天這篇文章要討論的核心內容。

介紹

從廣義上講,Android應用中的數據存儲選項共有五種主要類型:將數據保存在應用的共享偏好當中、保存在內部存儲(專屬于應用本身)當中、保存在外部存儲(向設備公開)當中、保存在數據庫當中以及保存在可通過設備互聯網連接訪問的Web資源當中。受篇幅所限,我們無法詳細對這些選項作出論述,但會對每種方案的基礎特性加以概括、從而幫助大家在需要使用持久化數據時理清存儲問題的解決思路。

1. 共享偏好

第一步

共享偏好允許大家以鍵-值對的形式保存基本數據類型。應用程序的共享偏好文件通常被視為最簡單的數據存儲選項,但從本質上說它對于存儲對象提出了一定程度的限制。大家可以通過它存儲基本類型數字(如整數、長數以及浮點數字)、布爾值以及文本字符串。我們需要為自己保存的每個數值分配一個名稱,從而在應用程序運行時據此對其進行檢索。由于大家很可能在自己創建的第一款應用中就用到共享偏好,因此我們人把它作為講解的重點、以更為詳盡的方式(相較于其它選項)進行表述,從而幫助各位鞏固必要知識。

大家可以在自己的主Activity類中嘗試這些代碼,并在稍后運行本系列教程的應用示例時對其加以測試。在理想情況下,共享偏好應該可以符合應用程序中的用戶配置選項,如同選擇外觀設置一樣。大家應該還記得,我們曾經創建過一個簡單的按鈕,用戶點擊它之后屏幕上會顯示出“Ouch”文本內容。現在讓我們假設自己希望用戶在點擊一次之后,該按鈕上會持續顯示“Ouch”字樣,且該狀態在應用程序運行過程中始終保持不變。這意味著按鈕上的初始文本僅在用戶首次點擊操作之前存在。

讓我們為應用程序添加共享偏好內容。在該類的起始位置、onCreate方法之前,我們為共享偏好選擇一個名稱:

 
  1. public?static?final?String?MY_APP_PREFS?=?"MyAppPrefs";?

利用“public static”修飾符,我們可以訪問處于應用內任何類中的這項變量,因此我們只需要將偏好名稱字符串保存在這里即可。我們使用大寫是因為該變量屬于常數,“final”修飾符也是因此而存在。每一次檢索或者在應用程序偏好當中設置數據條目時,大家都必須使用同樣的名稱。

第二步

現在我們來編寫共享偏好內容。在我們的onClick方法中、按鈕“Ouch”文本設置部分的下方,嘗試通過名稱取回這條共享偏好:

 
  1. SharedPreferences?thePrefs?=?getSharedPreferences(MY_APP_PREFS,?0);?

大家需要為“android.conent.SharedPreferences”類添加一條導入。將鼠標懸停在“SharedPreferences”文本上方,并利用Eclipse提示完成導入。第一項參數是我們所定義的偏好名稱,第二項則是我們作為默認選項的基本模式。

現在我們需要為共享偏好指定一套編輯器,從而實現對其中數值的設定:

 
  1. SharedPreferences.Editor?prefsEd?=?thePrefs.edit();?

現在我們可以向共享偏好當中寫入值了:

prefsEd.putBoolean("btnPressed", true);

這里我們使用了布爾類型,因為當前狀態只分為兩種——用戶已經或者尚未按下按鈕。編輯器提供多種不同類型,我們可以從中選擇以保存這套共享偏好,其中每種方法都擁有自己的名稱與值參數。最后,我們需要提交編輯結果:

 
  1. prefsEd.commit();?

第三步

現在讓我們利用已經保存的值來檢測用戶運行應用程序后,按鈕應該顯示什么樣的內容。在onCreate中的現有代碼之后添加共享偏好:

 
  1. SharedPreferences?thePrefs?=?getSharedPreferences(MY_APP_PREFS,?0);?

這一次我們不必使用編輯器,因為我們只需要獲取一個值:

 
  1. boolean?pressed?=?thePrefs.getBoolean("btnPressed",?false);?

現在我們利用已經設置過的名稱檢索該值,并讀取變量中的結果。如果該值尚未被設置,返回的則為第二項參數,也就是默認值——代表否定含義。現在讓我們使用該值:

 
  1. if(pressed)?theButton.setText("Ouch");?

如果用戶在應用程序運行之后按下該按鈕,則按鈕直接顯示“Ouch”字樣。在本系列的后續文章當中,大家會看到我們在應用運行中進行這一操作的情況。這個簡單的例子很好地詮釋了共享偏好的使用過程。大家會發現,共享偏好在幫助應用程序通過外觀及使用感受迎合用戶喜好方面具有重要的作用。

2. 私有內部文件

第一步

大家可以將文件保存在用戶設備的內部以及外部存儲當中。如果將文件保存在內部存儲中,Android系統會將其視為專屬于當前應用的私有數據。這類文件基本上屬于應用程序的組成部分,我們無法在應用程序之外直接對其進行訪問。再有,如果應用程序被移除、這些文件也會同時被清空。

大家可以利用以下輸出例程在內存存儲中創建一個文件:

 
  1. FileOutputStream?fileOut?=?openFileOutput("my_file",?Context.MODE_PRIVATE);?

大家需要為“java.io.FileOutputStream”類進行導入添加。我們提供了文件名稱與模式,選擇私有模式意味著該文件將只能被該應用程序所使用。如果大家現在就把這部分代碼加入到Activity當中,例如onClick方法中,Eclipse將彈出錯誤提示。這是因為當我們進行輸入/輸出操作時,應用程序可能遭遇一些需要應對的錯誤。如果大家的輸入/輸出操作無法解決這類錯誤,Eclipse就會提示異常狀況、應用程序也會中止運行。為了保證應用程序在這種情況下仍能正常運行,我們需要將自己的輸入/輸出代碼封裝在try代碼塊當中:

 
  1. try{?????FileOutputStream?fileOut?=?openFileOutput("my_file",?Context.MODE_PRIVATE);?
  2. }?catch(IOException?ioe){?????
  3. Log.e("APP_TAG",?"IO?Exception",?ioe);?}?

如果輸入/輸出操作導致異常,那么catch塊中的上述代碼就會付諸執行,從而將錯誤信息寫入到日志當中。大家今后會經常用到應用程序中的Log類(導入‘android.util.Log’),它會記錄代碼執行時所發生的具體情況。我們可以為字符串標簽定義一個類變量,也就是上述代碼中的第一條參數。這樣一旦出現錯誤,大家就可以在Android LogCat中查看異常信息了。

第二步

現在回到try塊,在創建了文件輸出例程之后,大家可以嘗試將以下代碼寫入文件:

 
  1. String?fileContent?=?"my?data?file?content";?fileOut.write(fileContent.getBytes());?

在將所有必要內容寫入數據文件之后,利用以下代碼作為結尾:

 
  1. fileOut.close();?

第三步

當大家需要檢索內部文件中的內容時,可以通過以下流程實現:

 
  1. try{????
  2. ?FileInputStream?fileIn?=?openFileInput("my_file");?????
  3. //read?the?file?}?catch(IOException?ioe){?????
  4. Log.e("APP_TAG",?"IO?Exception",?ioe);?}?

在try塊當中,利用利用緩沖讀取器讀取文件內容:

 
  1. InputStreamReader?streamIn?=?new?InputStreamReader(fileIn);?
  2. BufferedReader?fileRead?=?new?BufferedReader(streamIn);?
  3. StringBuilder?fileBuild?=?new?StringBuilder("");?
  4. String?fileLine=fileRead.readLine();?while(fileLine!=null){????
  5. ?fileBuild.append(fileLine+"\n");?????
  6. fileLine=fileRead.readLine();?}?
  7. String?fileText?=?fileBuild.toString();?streamIn.close();?

大家不要被其中所涉及的大量不同對象所嚇倒,這其實屬于標準的Java輸入/輸出操作。其中的while循環會在文件中的每一行執行一次。在執行完成后,“fileText”變量將把文件內容保存為字符串、以備我們直接使用。

3. 公共外部文件

第一步

只要用戶設備支持,我們的應用程序也可以將文件保存在外部存儲當中。外部存儲種類繁多,包括SD卡、其它便攜式介質或者用戶無法移除但被系統認定為外部類型的內存存儲機制。當我們將文件保存在外部存儲中時,其內容將完全公開、大家也無法以任何方式阻止用戶或者其它應用對其進行訪問。

在我們嘗試將數據保存在外部存儲中之前,必須首先檢查對應存儲機制是否可用——盡量避免意外狀況絕對是種好習慣:

 
  1. String?extStorageState?=?Environment.getExternalStorageState();?

系統會將信息以字符串的形式返回,大家可以對其進行分析、并與Environment類中的外部存儲狀態字段加以比對:

 
  1. if(Environment.MEDIA_MOUNTED.equals(extStorageState)){?????
  2. //ok?to?go?ahead?and?read/?write?to?external?storage?}?
  3. else?if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)){????
  4. ?//can?only?read?}?else{?????//cannot?read?or?write?}?

即使設備上確實存在外部存儲,我們也不能先入為主地假定應用可以向其寫入數據。

第二步

在證實了我們確實能夠向外部存儲寫入數據之后,大家接下來需要檢索目錄以指定文件保存的位置。以下應用程序設置內容指向八級及更高API:

 
  1. File?myFile?=?new?File(getExternalFilesDir(null),?"MyFile.txt");?

這樣大家就可以對該文件進行寫入與讀取了。不過也別忘了在項目的清單文件中添加以下僅限:

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

隨著我們開發的應用程序變得愈發復雜,大家可能希望將自己保存得到的文件與其它應用共享。在這種情況下,大家可以使用公共目錄下的各類通用條目,例如圖片以及音樂文件。

4. 數據庫

隨著我們的應用程序所涉及的復雜結構數據越來越多,共享偏好或者內部/外部文件可能已經無法滿足實際需求,這時候大家就應該考慮使用數據庫方案了。Android支持開發人員在應用程序內部創建并訪問SQLite數據庫。在我們創建一套數據庫時,其將作為私有組件服務單純服務于相關應用程序。

在Android應用中利用SQLite數據庫的方法多種多樣,推薦大家使用擴展SQLiteOpenHelper的類來實現這方面需求。在該類當中,我們需要定義數據庫屬性、創建各種類變量(包括我們所定義的數據庫列表名稱及其SQL創建字符串),具體代碼如下所示:

 
  1. private?static?final?String?NOTE_TABLE_CREATE?=?????"CREATE?TABLE?Note?(noteID?INTEGER?PRIMARY?KEY?AUTOINCREMENT,?"?+?????"noteTxt?TEXT);";?

這里所舉的例子只涉及一套非常簡單的表格,其中包含兩列,一列內容為ID、另一列內容為文本;兩列都用于記錄用戶注釋信息。在SQLiteOpenHelper類當中,大家可以重寫onCreate方法來創建自己的數據庫。在應用程序的其它部分當中,例如Activity類中,大家可以通過SQLiteOpenHelper實現對數據庫的訪問,并利用WritableDatabase方法插入新記錄、利用getReadableDatabase方法來查詢現有記錄,而后將結果顯示在應用程序UI當中。

在對查詢結果進行迭代時,我們的應用程序將使用Cursor類——該類會依次引用結果集中的每一行內容。

5. 互聯網數據

很多應用都會使用互聯網數據資源,而且某些應用甚至基本是由一套界面與大量Web數據源所構成。大家可以利用用戶設備上的互聯網連接來存儲并檢索來自Web的數據,只要網絡連接有效、這一機制就能正常運作。為了實現這一目標,我們需要在自己的清單文件中添加“android.permission.INTERNET”權限。

如果我們希望自己的應用能夠從互聯網中獲取數據,則必須保證這一流程脫離應用主UI線程。利用AsyncTask,大家可以通過后臺進程的方式從Web源獲取數據、在數據下載完成后將結果寫入UI、最后讓UI正常執行自身功能。

大家還可以將一個內部AsyncTask類添加到Activity類當中,并在需要獲取數據的時候在該Activity中創建一個AsyncTask實例。通過在AsyncTask中引入doInBackground與onPostExecute兩種方法,大家可以檢索Activity中所獲取到的數據并將其寫入用戶界面。

獲取Web數據在應用開發工作當中屬于中等難度的任務,大家最好在熟練掌握了Android開發知識之后再進行嘗試。不過大家可能很快就會發現,這樣的數據獲取機制對不少應用都非常適合,因為這能有效利用用戶設備的連接資源。Java與Android都提供相關工具,用于處理返回的結構化數據——例如JSON feed。

結論

在今天的文章中,我們基本了解了開發Android應用程序時需要接觸到的數據存儲方案。無論大家最終選擇哪種方案,都應該以實際需求作為參考標準,因為不同的方案只適合特定需求。在本系列教程的下一篇當中,我們將共同探討如何將物理設備與已安裝的Eclipse相連、同時學習如何創建虛擬設備。在此之后,我們還將探索如何讓應用程序運行在這兩種類型的設備之上。順便向大家報告,再有兩篇文章本系列教程就將徹底結束;在最后一篇文章中,我們將研究通用類以及Android Activity生命周期,從而幫助大家做好開發應用程序的一切準備。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457682.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457682.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457682.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設計微服務架構需要解決的問題

問題: 劃分服務的原則是什么服務之間選擇何種輕量級的通信協議如何做到服務的獨立部署如何確定使用何種編程語言?控制多語言帶來的復雜度如何做到服務的去中心化如何解決大量微服務引入的運維成本轉載于:https://www.cnblogs.com/fight-tao/p/5641286.html

Django Model設計詳解

Django Model 設計 Django Model設計是Django五項基礎核心設計之一(Model設計,URL配置,View編寫,Template設計,From使用),也是MVC模式中重要的環節。 如果圖片無法訪問,大家可以移…

python設置全局變量失敗_Python全局變量與global關鍵字常見錯誤解決方案

在Python的變量使用中,經常會遇到這樣的錯誤:local variable a referenced before assignment它的意思是:局部變量“a”在賦值前就被引用了。比如運行下面的代碼就會出現這樣的問題:a 3def Fuc():print (a)a a 1Fuc()? 但是如果把 a a …

Atititi tesseract使用總結

Atititi tesseract使用總結 消除bug,優化,重新發布。當前版本為3.02 項目下載地址為:http://code.google.com/p/tesseract-ocr。 Windows cmd命令行使用Tesseract-OCR引擎識別驗證碼: 1、下載安裝Tesseract-OCR引擎(3.0版本才支持中文識別) t…

Javascipt數組去重的幾種方式

方法一 function unique(arr) {var retArr [];for (var i 0; i < arr.length; i) {(retArr.indexOf(arr[i]) -1) && retArr.push(arr[i]);}return retArr; } 方法二 function unique(arr) {return arr.filter(function(item, index, array) {return array.indexO…

01_JS語法

JS語法 嚴格區分大小寫以;結尾&#xff0c;不寫瀏覽器會自動加&#xff0c;但不準確&#xff0c;且會占用瀏覽器資源自動忽略多個空格和換行 寫在哪 所有JS代碼都必須依托網頁運行 內嵌 寫在html的script標簽中 <script>// JS代碼 </script>事件 寫在某個ht…

pythonwhile循環love_python基礎之while循環及編碼

while 條件&#xff1a;循環體死循環&#xff1a;沒有終止條件(修改方法&#xff1a;1.改變條件2.使用break)break 終止當前循環contiune&#xff1a;跳出本次循環&#xff0c;繼續下次循環break和contione必須在循環體里while 條件&#xff1a;循環體else&#xff1a;結果當wh…

css頁面布局

居中布局 水平居中 父元素和子元素的寬度都未知 inline-block text-ailgn .child{display:inline-block;} .parent{text-align:center;} 優點&#xff1a;兼容性好 缺點&#xff1a;子元素文本繼承了text-align屬性&#xff0c;子元素要額外加text-align:left; table ma…

02_JS變量

JS變量 字面量 常量&#xff0c;不可變量 變量 變量用 var 變量名聲明 命名 變量命名以數字字母下劃線和$組成&#xff0c;不能以數字開頭&#xff0c;還可以是utf-8的任意字符&#xff0c;包括中文&#xff0c;一般采用駝峰命名法 常用的幾個函數 alert():瀏覽器彈窗d…

Rotate String

Given a string and an offset, rotate string by offset. (rotate from left to right) Example Given "abcdefg". offset0 > "abcdefg" offset1 > "gabcdef" offset2 > "fgabcde" offset3 > "efgabcd"分析&am…

音視頻播放、錄音、拍照

音頻 在iOS中音頻播放從形式上可以分為音效播放和音樂播放。前者主要指的是一些短音頻播放&#xff0c;通常作為點綴音頻&#xff0c;對于這類音頻不需要進行進度、循環等控制。后者指的是一些較長的音頻&#xff0c;通常是主音頻&#xff0c;對于這些音頻的播放通常需要進行精…

python 遞歸函數與循環的區別_提升Python效率之使用循環機制代替遞歸函數

斐波那契數列當年&#xff0c;典型的遞歸題目&#xff0c;斐波那契數列還記得嗎&#xff1f;def fib(n):if n1 or n2:return 1else:return fib(n-1)fib(n-2)當然, 為了程序健壯性&#xff0c;加上try...except...def fib(n):if isinstance(n, int):print(兄弟,輸入正整數哈)ret…

03_JS數據類型

JS數據類型 基本數據類型 String 字符串類型&#xff0c;申明時用單引號或雙引號引起來&#xff0c;兩種引號不可嵌套&#xff0c;不可混用 Number 數值型&#xff0c;有兩個特殊的數字 Infint:無窮大NaN&#xff1a;非數值型數字&#xff0c;不與任何類型相等 Boolean …

7.5

姓名 崔巍 時間 2016年7月5日 學習內容 最后一次確定同步控制力度等實現細節。 學習了Visual Studio C#軟件測試方面的工具。鞏固了等價類黑盒測試方法的相關理論&#xff0c;并且學習了集成測試、回歸測試的相關內容&#xff0c;并進行了測試。 集成測試&#xff0c;…

python scratch ev3_如何在scratch上連接樂高ev3?

樂高教育的官網有關于EV3使用Python的詳細介紹https://education.lego.com/zh-cn/support/mindstorms-ev3/python-for-ev3?education.lego.com來自網易有道Scratch是現在小朋友們最熱的編程工具&#xff0c;也是各學校和培訓機構對小學生編程的入門首選。網易有道Kada平臺是一…

04_JS運算符

JS運算符 一元運算符 -,正負號&#xff0c;對非數值類型做正負操作會先轉換成數值型&#xff0c;可以用快速進行類型轉換 邏輯運算符 且 &&&#xff0c;從左到右看&#xff0c;一旦返現值為false的表達式立刻返回false&#xff0c;全真為真或 ||&#xff0c;從左到右…

C語言 第八章 函數、指針與宏

一、函數 函數是一個包含完成一定功能的執行代碼段。我們可以把函數看成一個"黑盒子", 你只要將數據送進去就能得到結果, 而函數內部究竟是如何工作的的, 外部程序是不知道的。外部程序所知道的僅限于輸入給函數什么以及函數輸出什么。函數提供了編制程序的手段,使之…

ByteBuffer用法小結

在NIO中,數據的讀寫操作始終是與緩沖區相關聯的.讀取時信道(SocketChannel)將數據讀入緩沖區,寫入時首先要將發送的數據按順序填入緩沖區.緩沖區是定長的,基本上它只是一個列表,它的所有元素都是基本數據類型.ByteBuffer是最常用的緩沖區,它提供了讀寫其他數據類型的方法,且信道…

promise用法_Promise的秘密

寫在前面本篇文章將會帶大家從分解promise入手&#xff0c;一步步實現一個promise。但閱讀之前需要比較熟練地了解了解用法&#xff0c;結合用法看文章可能更容易理解。結構先看一下簡單的用法。const promise new Promise((resolve, reject) > {setTimeout(() > {resol…

SpringMVC視圖解析器(轉)

前言 在前一篇博客中講了SpringMVC的Controller控制器&#xff0c;在這篇博客中將接著介紹一下SpringMVC視圖解析器。當我們對SpringMVC控制的資源發起請求時&#xff0c;這些請求都會被SpringMVC的DispatcherServlet處理&#xff0c;接著Spring會分析看哪一個HandlerMapping定…