第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)_第1頁(yè)
第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)_第2頁(yè)
第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)_第3頁(yè)
第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)_第4頁(yè)
第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)_第5頁(yè)
已閱讀5頁(yè),還剩13頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

·PAGE16·Android數(shù)據(jù)庫(kù)程序設(shè)計(jì)·PAGE3·第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)第1章在Android系統(tǒng)中存儲(chǔ)數(shù)據(jù)今天,我們生活在一個(gè)越來(lái)越多地依賴以數(shù)據(jù)為中心和數(shù)據(jù)驅(qū)動(dòng)的世界當(dāng)中。如亞馬遜之類的公司對(duì)用戶查看和購(gòu)買的商品進(jìn)行信息跟蹤,以便能夠向用戶推薦更多類似產(chǎn)品;如Google這樣的公司,存儲(chǔ)通過(guò)它搜索的每一條查詢,以便在未來(lái)能夠提供更好的搜索查詢建議;類似Facebook這樣的社交媒體網(wǎng)站會(huì)記錄用戶與朋友之間的每一個(gè)事件,以便更好地了解數(shù)以百萬(wàn)計(jì)的用戶。我們生活在以數(shù)據(jù)為中心的世界,開(kāi)發(fā)以數(shù)據(jù)為中心的應(yīng)用程序正是我們的當(dāng)務(wù)之急。讀者可能會(huì)問(wèn),為什么會(huì)是Android?或者再通俗點(diǎn),為什么會(huì)是移動(dòng)應(yīng)用程序?在過(guò)去幾年中,智能手機(jī)和平板電腦等移動(dòng)設(shè)備使用量一直呈爆炸式的增長(zhǎng)。此外,移動(dòng)設(shè)備也隱含地給予在桌面應(yīng)用程序當(dāng)中所不具備的另一層面上的數(shù)據(jù)。當(dāng)隨身攜帶智能手機(jī)或平板電腦時(shí),會(huì)通過(guò)這些設(shè)備得到當(dāng)前所處的位置,也能夠知道在何處辦理手續(xù)或者在做些什么事情。簡(jiǎn)而言之,它所了解的可能比人們所能夠意識(shí)到的更多。記住以上兩點(diǎn)之后,現(xiàn)在使用Google已經(jīng)內(nèi)置在Android操作系統(tǒng)當(dāng)中的多種方法來(lái)探索數(shù)據(jù)以及Android系統(tǒng)本身。本書(shū)假定讀者都已經(jīng)具有一些Android操作系統(tǒng)方面的相關(guān)經(jīng)驗(yàn),因此在這里將會(huì)深入到具體的代碼層面上。但同樣重要的是讀者要知道所有可用的各種數(shù)據(jù)存儲(chǔ)方法,還需要理解每一種方法的優(yōu)劣,這樣才能夠創(chuàng)建高效的、易于設(shè)計(jì)和可伸縮的應(yīng)用程序。1.1使用SharedPreferencesSharedPreferences是Android應(yīng)用程序中存儲(chǔ)本地?cái)?shù)據(jù)最簡(jiǎn)單、快速和高效的方法。它的本質(zhì)是一個(gè)框架,允許用戶存儲(chǔ)并關(guān)聯(lián)每一個(gè)key-value(鍵-值)對(duì)到用戶的應(yīng)用程序(可以認(rèn)為是映射到應(yīng)用程序,以便用戶可以隨時(shí)訪問(wèn))。此外,由于每個(gè)應(yīng)用程序都與自己的SharedPreferences類相關(guān)聯(lián),因此被存儲(chǔ)以及提交的數(shù)據(jù)將會(huì)在所有用戶會(huì)話當(dāng)中得以體現(xiàn)。然而,由于其簡(jiǎn)單和高效的性質(zhì),SharedPreferences只允許用戶存儲(chǔ)原始數(shù)據(jù)類型,即boolean(布爾型)、float(浮點(diǎn)型)、long(長(zhǎng)整型)、int(整型)和string(字符型),因此在決定使用SharedPreferences存儲(chǔ)數(shù)據(jù)時(shí)要牢記這一點(diǎn)。下面是如何訪問(wèn)和使用應(yīng)用程序的SharedPreferences類的一個(gè)例子。publicclassSharedPreferencesExampleextendsActivity{ privatestaticfinalStringMY_DB="my_db"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //INSTANTIATESHAREDPREFERENCESCLASS SharedPreferencessp=getSharedPreferences(MY_DB, Context.MODE_PRIVATE); //LOADTHEEDITOR–REMEMBERTOCOMMITCHANGES! Editore=sp.edit(); e.putString("strKey","HelloWorld"); e.putBoolean("boolKey",true); mit(); StringstringValue=sp.getString("strKey","error"); booleanbooleanValue=sp.getBoolean("boolKey",false); Log.i("LOG_TAG","Stringvalue:"+stringValue); Log.i("LOG_TAG","Booleanvalue:"+booleanValue); }}首先來(lái)分析這段代碼:在這里首先啟動(dòng)一個(gè)Activity;此外,在onCreat()方法中,請(qǐng)求檢索SharedPreferences類。getSharedPreference()方法的語(yǔ)法是:getSharedPreferences(StringmapName,intmapMode)其中第一個(gè)參數(shù)指明了要映射的sharedpreference(每一個(gè)應(yīng)用程序可以擁有幾個(gè)單獨(dú)的sharedpreference,因此,就像在數(shù)據(jù)庫(kù)中指定表名一樣,必須指明要檢索的映射)。在上面的例子當(dāng)中的第二個(gè)參數(shù)有點(diǎn)復(fù)雜,將MODE_PRIVATE作為參數(shù),該參數(shù)只需指定要檢索的shared

preference實(shí)例的可見(jiàn)性(在例子中可見(jiàn)性設(shè)置為私有,這樣的話只有當(dāng)前的應(yīng)用程序才能訪問(wèn)映射的內(nèi)容)。其他模式如下。MODE_WORLD_READABLE:映射的內(nèi)容其他應(yīng)用程序可見(jiàn),但只讀。MODE_WORLD_WRITEABLE:其他應(yīng)用程序可對(duì)映射的內(nèi)容進(jìn)行讀寫。MODE_MULTI_PROCESS:該模式從APILevel11(Android3.0版本)開(kāi)始提供,允許用戶使用多個(gè)進(jìn)程修改,可能會(huì)寫入相同sharedpreference實(shí)例的映射?,F(xiàn)在,只要有了sharedpreference對(duì)象,就可以立即使用各種get()方法對(duì)內(nèi)容進(jìn)行檢索。例如前面提到的getString()和getBoolean()。get()方法通常有兩個(gè)參數(shù):第一個(gè)為key關(guān)鍵字,第二個(gè)參數(shù)在如果沒(méi)有找到給定key關(guān)鍵字的情況下,則為默認(rèn)值。在之前的那個(gè)例子當(dāng)中,就是用了如下的get()方法:StringstringValue=sp.getString("strKey","error");booleanbooleanValue=sp.getBoolean("boolKey",false);因此,在第一種情況下所要檢索的是與關(guān)鍵字strKey關(guān)聯(lián)的字符,如果沒(méi)有相關(guān)聯(lián)的關(guān)鍵字,那么默認(rèn)的字符串為error。類似地,在第二種情況下要檢索與boolKey關(guān)鍵字相關(guān)聯(lián)的布爾值,如果沒(méi)有這樣的鍵值存在,那么布爾值默認(rèn)為false。然而,如果要編輯(edit)內(nèi)容或添加新的(addnew)內(nèi)容,還要檢索每個(gè)sharedpreference實(shí)例包含的Editor對(duì)象。這個(gè)Editor對(duì)象包含所有允許用戶傳遞鍵及其相關(guān)值(例如標(biāo)準(zhǔn)Map對(duì)象)的put()方法。唯一需要注意的是,在添加或更新了sharedpreference的內(nèi)容后,需要調(diào)用Editor對(duì)象的commit()方法來(lái)落實(shí)更新。此外,就像一個(gè)標(biāo)準(zhǔn)的Map對(duì)象,Editor類也包含remove()和clear()方法,使用戶可以自由操作sharedpreference的內(nèi)容。在介紹使用SharedPreferences的典型用例之前,注意如果要將sharedpreference實(shí)例的可見(jiàn)性設(shè)置為MODE_WORLD_WRITEABLE,那么就可能會(huì)將自身暴露于那些有很多安全漏洞的眾多外部惡意應(yīng)用程序當(dāng)中。因此在實(shí)際應(yīng)用中并不推薦此模式。然而眾多開(kāi)發(fā)人員面臨在兩個(gè)應(yīng)用程序間共享信息的需求,其解決的方法是在所涉及的應(yīng)用程序清單文件中設(shè)置android:sharedUserID。它的工作原理是,每個(gè)應(yīng)用程序在簽名和導(dǎo)出時(shí),會(huì)自動(dòng)生成應(yīng)用程序ID。如果在應(yīng)用程序清單文件中明確設(shè)置了這個(gè)ID,假設(shè)兩個(gè)應(yīng)用程序使用相同的密鑰進(jìn)行簽名,那么它們就不需要將其數(shù)據(jù)暴露給用戶手機(jī)上其他應(yīng)用程序能夠自由地訪問(wèn)彼此的數(shù)據(jù)。換句話說(shuō),當(dāng)兩個(gè)應(yīng)用程序設(shè)置了相同的ID,這兩個(gè)(也只有這兩個(gè))應(yīng)用程序可以訪問(wèn)彼此的數(shù)據(jù)。1.2SharedPreferences的常見(jiàn)使用案例現(xiàn)在已經(jīng)知道如何實(shí)例化以及編輯一個(gè)sharedpreference對(duì)象,對(duì)這種類型的數(shù)據(jù)存儲(chǔ)需要考慮它的典型用例。接下來(lái)的幾個(gè)例子將會(huì)展示應(yīng)用程序所保存的那些小型的、原始鍵-值數(shù)據(jù)對(duì)的類型。1.2.1檢查用戶是不是第一次訪問(wèn)應(yīng)用程序大多數(shù)應(yīng)用程序在用戶第一次訪問(wèn)它時(shí),會(huì)顯示一些說(shuō)明/向?qū)Щ蛘邌?dòng)畫(huà)面的activity,如下所示:publicclassSharedPreferencesExample2extendsActivity{ privatestaticfinalStringMY_DB="my_db"; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); SharedPreferencessp=getSharedPreferences(MY_DB, Context.MODE_PRIVATE); /** *CHECKIFTHISISUSER'SFIRSTVISIT */ booleanhasVisited=sp.getBoolean("hasVisited",false); if(!hasVisited){ //... //SHOWSPLASHACTIVITY,LOGINACTIVITY,ETC //... //DON'TFORGETTOCOMMITTHECHANGE! Editore=sp.edit(); e.putBoolean("hasVisited",true); mit(); } }}1.2.2應(yīng)用程序最后一次更新時(shí)進(jìn)行檢查許多應(yīng)用程序會(huì)有一些緩存或者同步、內(nèi)建的功能等都可能會(huì)要求進(jìn)行常規(guī)更新。要節(jié)省更新時(shí)間,可以快速檢測(cè)距離上次更新已過(guò)去的時(shí)間,然后決定是否需要進(jìn)行更新或同步,代碼如下:/***CHECKLASTUPDATETIME*/longlastUpdateTime=sp.getLong("lastUpdateKey",0L);longtimeElapsed=System.currentTimeMillis()-lastUpdateTime;//YOURUPDATEFREQUENCYHEREfinallongUPDATE_FREQ=1000*60*60*24;if(timeElapsed>UPDATE_FREQ){//...//PERFORMNECESSARYUPDATES//...}//STORELATESTUPDATETIMEEditore=sp.edit();e.putLong("lastUpdateKey",System.currentTimeMillis());mit();下載本書(shū)例子的代碼用戶可以在Packt網(wǎng)站http://www.PacktP下載以用戶并填寫相關(guān)信息,將有電子郵件指引用戶進(jìn)行注冊(cè)。1.2.3保存用戶登錄用戶名一些應(yīng)用程序允許記住用戶自己的用戶名(例如PIN、電話號(hào)碼等其他面向登錄的字段),使用sharedpreference是存儲(chǔ)簡(jiǎn)單原始字符ID的好方法,代碼如下:/***CACHEUSERNAMEASSTRING*///TYPICALLYYOUWILLHAVEANEDITTEXTVIEW//WHERETHEUSERENTERSTHEIRUSERNAMEEditTextuserNameLoginText=(EditText)findViewById(R.id.login_editText);StringuserName=userNameLoginText.getText().toString();Editore=sp.edit();e.putString("userNameCache",userName);mit();1.2.4保存應(yīng)用程序的狀態(tài)有些應(yīng)用程序的功能可能會(huì)根據(jù)應(yīng)用程序的狀態(tài)發(fā)生變化。例如設(shè)置電話鈴聲的應(yīng)用程序,當(dāng)用戶指明在靜音時(shí)不啟動(dòng)任何程序,那么這個(gè)重要的狀態(tài)需要被保存下來(lái),如下所示:/***REMEBERINGACERTAINSTATE*/booleanisSilentMode=sp.getBoolean("isSilentRinger",false);if(isSilentMode){//...//TURNOFFAPPLICATION//...}1.2.5緩存用戶的位置信息任何基于位置的應(yīng)用程序都會(huì)有多種原因(可能是用戶關(guān)掉了GPS,或者信號(hào)微弱等)要緩存用戶最后所處的位置信息。這可以將用戶的經(jīng)緯度轉(zhuǎn)換為一個(gè)浮點(diǎn)數(shù)后存儲(chǔ)在sharedpreference實(shí)例當(dāng)中簡(jiǎn)單地實(shí)現(xiàn)該功能,如下所示:/***CACHINGALOCATION*///INSTANTIATELOCATIONMANAGERLocationManagerlocationManager=(LocationManager)this.getSystemService(Context.LOCATION_SERVICE);//...//IGNORELOCATIONLISTENERSFORNOW//...LocationlastKnownLocation=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);floatlat=(float)lastKnownLocation.getLatitude();floatlon=(float)lastKnownLocation.getLongitude();Editore=sp.edit();e.putFloat("latitudeCache",lat);e.putFloat("longitudeCache",lon);mit();在最新的Android版本(APILevel11,即Android3.0)中,提供了新的getStringSet()方法用于針對(duì)一個(gè)給定的關(guān)聯(lián)鍵來(lái)設(shè)置和檢索字符串對(duì)象集,其具體操作代碼如下:Set<String>values=newHashSet<String>();values.add("Hello");values.add("World");Editore=sp.edit();e.putStringSet("strSetKey",values);mit();Set<String>ret=sp.getStringSet(values,newHashSet<String>());for(Stringr:ret){ Log.i("SharedPreferencesExample","Retrievedvals:"+r);}使用這種方法的例子很多,不過(guò)這里不得不暫時(shí)告一段落。1.3內(nèi)部存儲(chǔ)方法本節(jié)講解Android的內(nèi)部存儲(chǔ)機(jī)制。對(duì)于那些具有標(biāo)準(zhǔn)Java編程經(jīng)驗(yàn)的人來(lái)說(shuō),本節(jié)的內(nèi)容會(huì)感覺(jué)到相當(dāng)熟悉。Android的內(nèi)部存儲(chǔ)只允許讀寫與程序內(nèi)部?jī)?nèi)存相關(guān)聯(lián)的文件,這些文件只允許本應(yīng)用程序訪問(wèn),其他的應(yīng)用程序或用戶都不能訪問(wèn)。此外,當(dāng)刪除應(yīng)用程序時(shí),這些文件也會(huì)自動(dòng)被刪除。下面是如何訪問(wèn)應(yīng)用程序內(nèi)部存儲(chǔ)的簡(jiǎn)單例子。publicclassInternalStorageExampleextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //THENAMEOFTHEFILE StringfileName="my_file.txt"; //STRINGTOBEWRITTENTOFILE Stringmsg="HelloWorld."; try{ //CREATETHEFILEANDWRITE FileOutputStreamfos=openFileOutput(fileName, Context.MODE_PRIVATE); fos.write(msg.getBytes()); fos.close(); }catch(IOExceptione){ e.printStackTrace(); } }}這里簡(jiǎn)單地使用了Context類的openFileOutput()方法,該方法的第一個(gè)參數(shù)作為要?jiǎng)?chuàng)建(或覆蓋)的文件名,第二個(gè)參數(shù)為其可見(jiàn)性(與SharedPreferences類似,可以控制文件的可見(jiàn)性)。這樣它將會(huì)把想要寫入的字符串轉(zhuǎn)換為字節(jié)形式,并傳遞到輸出流write()方法。另外,需要注意的是,在openFileOutput()方法中使用到另外一種模式,如下所示。MODE_APPEND:該模式允許用戶打開(kāi)現(xiàn)有的文件,并在原有內(nèi)容的后面添加字符串(其他任何模式當(dāng)中現(xiàn)有的內(nèi)容將會(huì)被刪除)。此外,如果在Eclipse中進(jìn)行開(kāi)發(fā),可以轉(zhuǎn)到DDMS界面中查看應(yīng)用程序的內(nèi)部文件(當(dāng)中還包括其他一些內(nèi)容),如圖1-1所示。圖1-1現(xiàn)在就可以看到剛才所創(chuàng)建的文本文件。在使用移動(dòng)終端進(jìn)行開(kāi)發(fā)時(shí),該文件的路徑為/data/data/{your-app-path}/files/my_file.txt。然而,此時(shí)讀取回來(lái)的文件會(huì)比較冗長(zhǎng),下面是處理的代碼:publicclassInternalStorageExample2extendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //THENAMEOFTHEFILE StringfileName="my_file.txt"; try{ //OPENFILEINPUTSTREAMTHISTIME FileInputStreamfis=openFileInput(fileName); InputStreamReaderisr=newInputStreamReader(fis); //READSTRINGOFUNKNOWNLENGTH StringBuildersb=newStringBuilder(); char[]inputBuffer=newchar[2048]; intl; //FILLBUFFERWITHDATA while((l=isr.read(inputBuffer))!=-1){ sb.append(inputBuffer,0,l); } //CONVERTBYTESTOSTRING StringreadString=sb.toString(); Log.i("LOG_TAG","Readstring:"+readString); //CANALSODELETETHEFILE deleteFile(fileName); }catch(IOExceptione){ e.printStackTrace(); } }}在上面的代碼中,首先打開(kāi)文件輸入流,并將其傳遞到流讀取器。這可以調(diào)用read()方法,并且按照字節(jié)讀取數(shù)據(jù),這些數(shù)據(jù)隨后可以附加到一個(gè)StringBuilder中。一旦內(nèi)容充分讀取,只需從StringBuilder中返回字符(String)即可。最后,出于完整性目的,Context類給用戶提供了刪除保存在內(nèi)部存儲(chǔ)中文件的簡(jiǎn)單方法。1.4外部存儲(chǔ)方法外部存儲(chǔ),換句話說(shuō),就是將數(shù)據(jù)和文件存儲(chǔ)到手機(jī)的外部SD(SecureDigital)卡SharedPreferences之間的利弊。由于shared

preference的開(kāi)銷較小,所以其讀寫到一個(gè)簡(jiǎn)單的Map對(duì)象的效率要比讀寫到磁盤的高。然而,因?yàn)閮H限于簡(jiǎn)單的原始值(在大多數(shù)情況下,最新的Android版本允許用戶保存字符串集),所以基本上就是針對(duì)效率去權(quán)衡其中的靈活性?;趦?nèi)部存儲(chǔ)和外部存儲(chǔ)機(jī)制,用戶可以不只是保存大塊的數(shù)據(jù)(如整個(gè)XML文件),還可以是形式較為復(fù)雜的數(shù)據(jù)(如媒體文件、圖像文件等)。那么內(nèi)部存儲(chǔ)和外部存儲(chǔ)有什么區(qū)別?這兩者的利弊較為微妙。一方面,在占用的存儲(chǔ)空間(memory)上,雖然取決于用戶所擁有的設(shè)備,但常見(jiàn)的內(nèi)部?jī)?nèi)存大小往往會(huì)比較低,甚至是相對(duì)較新的手機(jī)的內(nèi)部存儲(chǔ)器空間也少于512MB(譯者注:本書(shū)翻譯時(shí),手機(jī)內(nèi)部存儲(chǔ)器最大已經(jīng)達(dá)到64GB)。另一方面,外部存儲(chǔ)則根據(jù)用戶在手機(jī)里使用什么樣的SD卡來(lái)決定。通常情況下,如果使用了SD卡,則外部存儲(chǔ)的容量會(huì)比內(nèi)部存儲(chǔ)大很多(根據(jù)SD卡的容量,其最大可達(dá)32GB)?,F(xiàn)在,比較一下內(nèi)部存儲(chǔ)和外部存儲(chǔ)的存取速度(accessspeed)。然而,在這種情況下,由于內(nèi)部存儲(chǔ)的讀寫速度完全依賴于手機(jī)使用的內(nèi)部閃存類型來(lái)決定,外部存儲(chǔ)也是這個(gè)道理,兩者之間的比較并沒(méi)有什么定論。最后需要考慮的一點(diǎn)是每種類型存儲(chǔ)機(jī)制的可訪問(wèn)性(accessibility)。內(nèi)部存儲(chǔ)的數(shù)據(jù)只能由該應(yīng)用程序訪問(wèn),這就比讓很多的外部惡意程序訪問(wèn)要安全得多。其缺點(diǎn)是一旦刪除應(yīng)用程序,那么內(nèi)部?jī)?nèi)存的數(shù)據(jù)也會(huì)被擦除。對(duì)于外部存儲(chǔ),由于它的可見(jiàn)性是大范圍的可讀和可寫,所以存儲(chǔ)在其上的任何文件都暴露于外部應(yīng)用程序和用戶之下,這對(duì)文件的安全和可靠沒(méi)有任何保證?,F(xiàn)在我們已經(jīng)了解了它們之間的一些不同點(diǎn),接下來(lái)再次回到代碼當(dāng)中,用下面的例子看看如何去訪問(wèn)外部SD卡。publicclassExternalStorageExampleextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); StringfileName="my_file.txt"; Stringmsg="HelloWorld."; booleanexternalAvailable=false; booleanexternalWriteable=false; Stringstate=Environment.getExternalStorageState(); if(state.equals(Environment.MEDIA_MOUNTED)){ //HEREMEDIAISBOTHAVAILABLEANDWRITEABLE externalAvailable=true; externalWriteable=true; }elseif (state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)){ //HERESDCARDISAVAILABLEBUTNOTWRITEABLE externalAvailable=true; }else{ //HEREFAILURECOULDBERESULTOFMANYSITUATIONS //NOOP } if(externalAvailable&&externalWriteable){ //FORAPILEVEL7ANDBELOW //RETRIEVESDCARDDIRECTORY Filer=Environment.getExternalStorageDirectory(); Filef=newFile(r,fileName); try{ //NOTEDIFFERENTFROMINTERNALSTORAGEWRITER FileWriterfWriter=newFileWriter(f); BufferedWriterout=newBufferedWriter(fWriter); out.write(msg); out.close(); }catch(IOExceptione){ e.printStackTrace(); } }else{ Log.e("LOG_TAG","SDCARDUNAVAILABLE"); } }}要執(zhí)行上面的代碼,需要將WRITE_EXTERNAL_STORAGE權(quán)限添加到清單文件中。這里首先開(kāi)始調(diào)用Environment類的getExternalStorageState()方法,這樣能夠檢測(cè)外部SD卡是否已經(jīng)被裝載并可寫。在沒(méi)有執(zhí)行這些初步的檢查之前就嘗試(向外部SD卡)讀寫文件將引發(fā)錯(cuò)誤。一旦確認(rèn)SD卡已經(jīng)被加載并且可寫,在APILevel7(Android2.1)和較老的版本中,可以調(diào)用getExternalStorageDirectory()方法從SD卡的根目錄上獲取文件路徑。這里只需創(chuàng)建新的文件,并實(shí)例化FileWriter和BufferedWriter,再將字符串寫入文件即可。需要注意的是,這里處理外部存儲(chǔ)寫入磁盤時(shí)的方法不同于之前提到的寫入內(nèi)部存儲(chǔ)磁盤的方法。這一點(diǎn)需要多加注意和理解,為此本書(shū)很注重這些寫入方法。在內(nèi)部存儲(chǔ)的實(shí)例中通過(guò)調(diào)用Context類的openFileOutput()方法(該方法的第二個(gè)參數(shù)為模式)獲得了FileOutputStream對(duì)象。當(dāng)傳遞MODE_PRIVATE時(shí)后臺(tái)則創(chuàng)建一個(gè)文件,并寫入FileOutputStream,該文件由前述的應(yīng)用程序唯一ID進(jìn)行加密和簽名,這樣其他外部應(yīng)用程序就不能隨便訪問(wèn)這些文件的內(nèi)容。但是,當(dāng)在外部存儲(chǔ)中創(chuàng)建和寫入文件時(shí),默認(rèn)情況下它們并沒(méi)有相關(guān)的強(qiáng)制安全機(jī)制,所以應(yīng)用程序(或用戶)可以直接對(duì)這些文件進(jìn)行讀寫。這就是為什么用戶可以使用標(biāo)準(zhǔn)的Java方法(如FileWriter)寫入外部存儲(chǔ),而不能寫入內(nèi)部存儲(chǔ)的原因。最后,注意在Eclipse的DDMS視圖中創(chuàng)建的文件,假設(shè)安裝了SD卡,可以很容易在DDMS中查看剛剛創(chuàng)建的文本文件,如圖1-2所示。圖1-2所以在開(kāi)發(fā)應(yīng)用程序時(shí),通過(guò)DDMS視圖可以很快地填入、取出以及監(jiān)控寫入磁盤的文件。緊接著介紹從APILevel8(Android2.2)版本后寫入外部存儲(chǔ)的一些變更。在http:///reference/android/content/Context.html#getExternalFilesDir(java.lang.String)網(wǎng)頁(yè)中有這些變更的相關(guān)文檔。但是在APILevel8(Android

2.2)和更高版本中,則會(huì)使用以下這兩種主要的新方法:getExternalFilesDir(Stringtype)getExternalStoragePublicDirectory(Stringtype)可能會(huì)注意到此時(shí)能傳遞到類型參數(shù)的每一個(gè)方法。這些類型的參數(shù)允許用戶指定文件的類型,以便分類到相應(yīng)的子目錄。上述第一種方法返回的外部文件目錄的根是特定于用戶應(yīng)用程序的,以便在卸載應(yīng)用程序時(shí)能夠刪除外部SD卡的關(guān)聯(lián)文件。第二種方法的文件目錄的根是公共的,以便在這些路徑里的文件即使是在應(yīng)用程序被卸載時(shí)還能保留。使用哪一種方法,取決于用戶要保存的文件類型。例如,如果是要在應(yīng)用程序中播放的媒體文件,那么用戶在決定卸載應(yīng)用程序時(shí)可能就不再需要該文件了。但是如果應(yīng)用程序允許用戶給自己的手機(jī)下載壁紙,那么在這種情況下,可能會(huì)考慮將這些圖片文件保存到一個(gè)公共的目錄,這樣即使卸載了應(yīng)用程序,那么這些文件還可以被系統(tǒng)所訪問(wèn)。在這里可以指定的不同類型(type)的參數(shù)如下:DIRECTORY_ALARMSDIRECTORY_DCIMDIRECTORY_DOWNLOADSDIRECTORY_MOVIESDIRECTORY_MUSICDIRECTORY_NOTIFICATIONSDIRECTORY_PICTURESDIRECTORY_PODCASTSDIRECTORY_RINGTONES在總結(jié)了對(duì)內(nèi)部和外部存儲(chǔ)機(jī)制的討論后,接下來(lái)開(kāi)始介紹SQLite數(shù)據(jù)庫(kù)這個(gè)更重要的內(nèi)容。1.5SQLite數(shù)據(jù)庫(kù)同樣重要的是,使用SQLite數(shù)據(jù)庫(kù)是截止目前為止最先進(jìn)和最強(qiáng)大的本地存儲(chǔ)方法。每個(gè)應(yīng)用程序都帶有自己的SQLite數(shù)據(jù)庫(kù),可以被應(yīng)用程序當(dāng)中的任何類進(jìn)行訪問(wèn),而不能由外部程序訪問(wèn)。在介紹更復(fù)雜的查詢或代碼段之前,在這里先快速瀏覽一下SQLite數(shù)據(jù)庫(kù)的要點(diǎn)。結(jié)構(gòu)化查詢語(yǔ)言(StructuredQueryLanguage,SQL)是專門用于在關(guān)系數(shù)據(jù)庫(kù)中管理數(shù)據(jù)的編程語(yǔ)言。關(guān)系數(shù)據(jù)庫(kù)允許用戶提交插入、刪除、更新和查詢等操作,同時(shí)還允許創(chuàng)建和修改數(shù)據(jù)庫(kù)模式(簡(jiǎn)單地說(shuō),就是數(shù)據(jù)庫(kù)中的各個(gè)表)。SQLite是MySQL、PostgreSQL和其他較為流行的數(shù)據(jù)庫(kù)系統(tǒng)的輕量化版本。它獨(dú)立且不依賴于服務(wù)器,是事務(wù)性的,并能執(zhí)行標(biāo)準(zhǔn)SQL語(yǔ)言查詢。其獨(dú)立性和可執(zhí)行性使其顯得高效而靈活,并且可在多種平臺(tái)上使用各種編程語(yǔ)言進(jìn)行訪問(wèn)(包括Android平臺(tái))?,F(xiàn)在來(lái)看看如何實(shí)例化一個(gè)SQLite數(shù)據(jù)庫(kù)模式,并且使用下面的代碼片段來(lái)創(chuàng)建一個(gè)非常簡(jiǎn)單的表:publicclassSQLiteHelperextendsSQLiteOpenHelper{ privatestaticfinalStringDATABASE_NAME="my_database.db"; //TOGGLETHISNUMBERFORUPDATINGTABLESANDDATABASE privatestaticfinalintDATABASE_VERSION=1; //NAMEOFTABLEYOUWISHTOCREATE publicstaticfinalStringTABLE_NAME="my_table"; //SOMESAMPLEFIELDS publicstaticfinalStringUID="_id"; publicstaticfinalStringNAME="name"; SQLiteHelper(Contextcontext){ super(context,DATABASE_NAME,null,DATABASE_VERSION); } @Override publicvoidonCreate(SQLiteDatabasedb){ db.execSQL("CREATETABLE"+TABLE_NAME+"("+UID+" INTEGERPRIMARYKEYAUTOINCREMENT,"+NAME +"VARCHAR(255));"); } @Override publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion, intnewVersion){ Log.w("LOG_TAG","Upgradingdatabasefromversion"+ oldVersion+"to"+newVersion+", whichwilldestroyallolddata"); //KILLPREVIOUSTABLEIFUPGRADED db.execSQL("DROPTABLEIFEXISTS"+TABLE_NAME); //CREATENEWINSTANCEOFTABLE onCreate(db); }}首先要注意的是:要?jiǎng)?chuàng)建可自定義的數(shù)據(jù)庫(kù)模式,需要重寫SQLiteOpenHelper類。重寫該類后,接下來(lái)就可以重寫允許改寫表結(jié)構(gòu)的onCreate()方法。在這個(gè)例子當(dāng)中,僅創(chuàng)建了一個(gè)包含兩個(gè)列的表:一個(gè)ID列和一個(gè)name列。這就等效于在SQL中運(yùn)行如下命令:CREATETABLEmy_table(_idINTEGERPRIMARYKEYAUTOINCREMENT,nameVARCHAR(255));這里ID列指定為主鍵PRIMARYKEY,并且為自增量AUTOINCREMENT,這實(shí)際上是Android系統(tǒng)中在創(chuàng)建所有表時(shí)所推薦的操作,在這里將會(huì)一直按照該標(biāo)準(zhǔn)進(jìn)行創(chuàng)建。最后,name列的寬度設(shè)置為最大255個(gè)字符(對(duì)于較長(zhǎng)的字符串,可以將列設(shè)置為L(zhǎng)ONGTEXT,即長(zhǎng)文本型)。在重寫onCreate()方法之后,還要重寫onUpgrade()方法。這些操作使用戶能夠快速而簡(jiǎn)單地修改表的結(jié)構(gòu)。所需要做的就是自動(dòng)增加DATA_VERSION的數(shù)值。在下次實(shí)例化SQLiteHelper時(shí),它將會(huì)自動(dòng)調(diào)用onUpgrade()方法,此時(shí)就會(huì)首先刪除數(shù)據(jù)庫(kù)的舊版本號(hào),然后再創(chuàng)建新的版本號(hào)。最后,快速看一下如何在基本空白的數(shù)據(jù)表中插入記錄和查詢數(shù)值,如下所示:publicclassSQLiteExampleextendsActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //INITOURSQLITEHELPER SQLiteHelpersqh=newSQLiteHelper(this); //RETRIEVEAREADABLEANDWRITEABLEDATABASE SQLiteDatabasesqdb=sqh.getWritableDatabase(); //METHOD#1:INSERTUSINGCONTENTVALUECLASS ContentValuescv=newContentValues(); cv.put(SQLiteHelper.NAME,"jasonwei"); //CALLINSERTMETHOD sqdb.insert(SQLiteHelper.TABLE_NAME,SQLiteHelper.NAME, cv); //METHOD#2:INSERTUSINGSQLQUERY StringinsertQuery="INSERTINTO"+ SQLiteHelper.TABLE_NAME+ "("+SQLiteHelper.NAME+")VALUES('jwei')"; sqdb.execSQL(insertQuery); //METHOD#1:QUERYUSINGWRAPPERMETHOD Cursorc=sqdb.query(SQLiteHelper.TABLE_NAME, newString[]{SQLiteHelper.UID,SQLiteHelper.NAME},null,null, null,null,null); while(c.moveToNext()){ //GETCOLUMNINDICES+VALUESOFTHOSECOLUMNS intid=c.getInt(c.getColumnIndex(SQLiteHelper.UID)); Stringname= c.getString(c.getColumnIndex(SQLiteHelper.NAME)); Log.i("LOG_TAG","ROW"+id+"HASNAME"+name); } c.close(); //METHOD#2:QUERYUSINGSQLSELECTQUERY Stringquery="SELECT"+SQLiteHelper.UID+","+ SQLiteHelper.NAME+"FROM"+SQLiteHelper.TABLE_NAME; Cursorc2=sqdb.rawQuery(query,null); while(c2.moveToNext()){ intid= c2.getInt(c2.getColumnIndex(SQLiteHelper.UID)); Stringname= c2.getString(c2.getColumnIndex(SQLiteHelper.NAME)); Log.i("LOG_TAG","ROW"+id+"HASNAME"+name); } c2.close(); //CLOSEDATABASECONNECTIONS sqdb.close(); sqh.close();

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論