在Android 應用程式之間資料共用—-ContentResolver中,已經說明了Android是如何?應用程式之間資料共用的,並詳細解析了如何擷取其他應用程式共用的資料。ContentProviders儲存和檢索資料,通過它可以讓所有的應用程式訪問到,這也是應用程式之間唯一共用資料的方法。那麼如何將應用程式的資料暴露出去? 通過以前文章的學習,知道ContentResolver是通過ContentProvider來擷取其他與應用程式共用的資料,那麼ContentResolver與ContentProvider的介面應該差不多的。 其中ContentProvider負責
ContentResolver則負責
- 擷取ContentProvider提供的資料;
- 修改/添加/刪除更新資料等;
ContentProvider 是如何向外界提供資料的? Android提供了ContentProvider,一個程式可以通過實現一個ContentProvider的抽象介面將自己的資料完全暴露出去,而且ContentProviders是以類似資料庫中表的方式將資料暴露,也就是說ContentProvider就像一個“資料庫”。那麼外界擷取其提供的資料,也就應該與從資料庫中擷取資料的操作基本一樣,只不過是採用URI來表示外界需要訪問的“資料庫”。至於如何從URI中識別出外界需要的是哪個“資料庫”,這就是Android底層需要做的事情了,不在此詳細說。簡要分析下ContentProvider向外界提供資料操作的介面: query(Uri, String[], String, String[], String) insert(Uri, ContentValues) update(Uri, ContentValues, String, String[]) delete(Uri, String, String[]) 這些操作與資料庫的操作基本上完全一樣,在此不詳細說,具體的解析可以參考Android Sqlite解析篇中的詳細說明。需要特殊說明的地方是URI: 在URI的D部分可能包含一個_ID ,這個應該出現在SQL語句中的,可以以種特殊的方式出現,這就要求我們在提供資料的時候,需要來額外關注這個特殊的資訊。Android SDK推薦的方法是:在提供資料表欄位中包含一個ID,在建立表時INTEGER PRIMARY KEY AUTOINCREMENT標識此ID欄位。 ContentProvider 是如何組織資料的? 組織資料主要包括:儲存資料,讀取資料,以資料庫的方式暴露資料。資料的儲存需要根據設計的需求,選擇合適的儲存結構,首選資料庫,當然也可以選擇本地其他檔案,甚至可以是網路上的資料。資料的讀取,以資料庫的方式暴露資料這就要求,無論資料是如何儲存的,資料最後必須以資料的方式訪問。 可能還有2個問題,是需要關注的。
- ContentProvider是什麼時候建立的,是誰建立的?訪問某個應用程式共用的資料,是否需要啟動這個應用程式?這個問題在Android SDK中沒有明確說明,但是從資料共用的角度出發,ContentProvider應該是Android在系統啟動時就建立了,否則就談不上資料共用了。這就要求在AndroidManifest.XML中使用<provider>元素明確定義。
- 可能會有多個程式同時通過ContentResolver訪問一個ContentProvider,會不會導致像資料庫那樣的“髒資料”?這個問題一方面需要資料庫訪問的同步,尤其是資料寫入的同步,在AndroidManifest.XML中定義ContentProvider的時候,需要考慮是<provider>元素multiprocess屬性的值;另外一方面Android在ContentResolver中提供了notifyChange()介面,在資料改變時會通知其他ContentObserver,這個地方應該使用了觀察者模式,在ContentResolver中應該有一些類似register,unregister的介面。
至此,已經對ContentProvider提供了比較全面的分析,至於如何建立ContentProvider,可通過2種方法:建立一個屬於你自己的ContentProvider或者將你的資料添加到一個已經存在的ContentProvider中,當然前提是有相同資料類型並且有寫入Content provider的許可權。在Android SDK的sample中提供的Notepad具體執行個體中去看原始碼! Android SQLite解析 By: 海市蜃樓 | In: Android開發 17 八 2009 說到SQLite,無論C++、Java程式員還是其他的非主流程式員,應該都聽說過它,可見其非常流行。SQLite是輕量級的、嵌入式的、關係型資料庫,目前已經在iPhone、Android等手機系統中使用,而且被其他的公司廣泛使用,比如說:Adobe,具體SQLite的介紹可以到其官方網站瀏覽。 在學習Android SQLite前,必須對SQL語句有很深入的瞭解(如果忘記了,利用這次機會好好複習下)。關於資料庫、表的建立等基礎知識,由於篇幅有限就不在此詳細說明,主要說明資料庫的4大基本操作:添加(insert)、刪除(delete)、查詢(query)、修改(update),這是在學習Android SQLite的過程中最為關注的部分。除了這4大操作以外,我們還需要注意的地方就是:擷取查詢結果的記錄集(Recordset)。 Android SQLite分析 等有了這些基本概念,再來學習Android SQLite,從Android SDK中摘要如下: 首先關注到的是SQLiteDatabase類,在Android SDK中看其詳細說明,其主要介面如下:
傳回值 |
函數原型 |
long |
insert(String table, String nullColumnHack, ContentValues values)Convenience method for inserting a row into the database. |
Int |
delete(String table, String whereClause, String[] whereArgs)Convenience method for deleting rows in the database. |
Cursor |
query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)Query the given table, returning a Cursor over the result set. |
Int |
update(String table, ContentValues values, String whereClause, String[] whereArgs)Convenience method for updating rows in the database. |
看到這些是不是感到似曾相識了?不錯,這就是資料庫的4大基本操作:添加(insert)、刪除(delete)、查詢(query)、修改(update)。感覺輕鬆很多了,再仔細看下這些函數的參數,發現很多參數都是按照SQL語句定義的, 例如:select * from p_employee where id <>’9999′ order by id asc 需要額外說明2個資料結構: ContentValues,Cursor; ContentValues就相當於C++中的map[(String key, Integer value)],其主要介面包括put(),get()。再結合insert操作的主要目的:按照表中資料區段將對應的資料項目寫入到表中,就可以看出來ContentValues主要是存放表中每個表的資料區段,以及其對應的值。 Cursor也就是前面說的:查詢結果的記錄集。從屬記錄集的特徵可以想到其包含的操作應該有:MoveFirst()、MoveLast()、MoveNext()、Move()、IsLast()、GetColumns()等,而且它還是個抽象類別[abstract class],SQLiteCursor就是其具體的實現。 關於SQLiteDatabase類,其他值得關注的函數是:Create()、execSQL()。至於其他的函數,比如beginTransaction(),endTransaction()等關於資料庫同步操作的函數,就只有在使用的過程中深入瞭解。 額外補充說明 最後值得一提的是:一個很好的輔助類SQLiteOpenHelper,其簡化了資料庫的操作。按照Android SDK文檔中的說明,也可以通過繼承此類、改寫其介面的方法來實現對資料庫的操作,SQLiteOpenHelper,其主要介面如下: 仔細分析其說明,發現這個類主要是建立一個資料庫,並對資料庫的版本進行管理。當在程式中調用這個類的方法getWritableDatabase()或者getReadableDatabase()方法的時候,如果當時沒有資料庫,那麼Android系統就會自動建立一個資料資料庫。 其他輔助說明
- 所有的資料庫檔案存放在手機中的/data/data/package_name/databases路徑下。最為重要的一點是:在Android中,所有的應用軟體的資料(包括檔案、資料庫)為該應用軟體所私人的,如果需要在不同的應用中共用資料,必須使用ContentProvider實現,一個ContentProvider類實現了一組標準的方法介面,從而能夠讓其他的應用儲存或讀取此ContentProvider的各種資料類型。
- 為了方便測試,如何查看SQLite資料庫的內容?使用Android SDK提供的工具:sqlite3.exe。這是一個命令列工具 + 生產力,列舉主要使用的命令如下:查看錶結構 sqlite3 “path” .dump
例如 G:\android\android-sdk-window\tools>sqlite3 30m.db3 .bump, 運行結構如下:BEGGIN TRANSACTION; CREATE TABLE [TmProgramm] ([index] INTEGER,[nID] INTEGER, [nChannelID] INTEGER,[strTitle] CHAR(255), [dwDuration] INTEGER, [strThumbNail] CHAR(1024),[strURL] CHAR(255),[strPathName] CHAR(255), [strAuthor] CHAR(255),[dwSize] INTEGER,[State] INTEGER,[Percent] INTEGER, [strConverted] CHAR(255),[dwVideoType] INTEGER,[dwDownloadedBytes] INTEGER,[strTime] CHAR(255), [strHTTPVersion] CHAR(255),[strUserAgent] CHAR(255),[strReferer] CHAR(255)); COMMIT; 這就是當初建立資料庫的語句 查看錶中的內容 sqlite3 “path” .schema 具體運行結果可以下載資料庫檔案30m.db3,在命令列中運行就可以看到了 其他協助命令查詢 sqlite3 .help
總結說明 通過對以上的學習,簡單寫了個資料庫的例子(moandroid.database.zip),大家可以參考下。 Android資料存放區(總結篇) By: 海市蜃樓 | In: Android開發 25 八 2009 在前面的2篇文章:Android SQLite解析、Android 應用程式之間資料共用中分別詳細說明了,如何使用資料庫儲存資訊,以及如何通過ContentProvider擷取其他應用程式共用的資料,現將Android資料存放區做下總結,在以後的開發過程中根據需求選擇合適的資料存放區方式。 Android提供了5種方式儲存資料:
- 使用SharedPreferences儲存資料;
- 檔案儲存體資料;
- SQLite資料庫儲存資料;
- 使用ContentProvider儲存資料;
- 網路儲存資料;
其中3,4已經在Android SQLite解析、Android 應用程式之間資料共用篇幅中詳細說明,不在此重複說明,現將其他3種方式詳細介紹。 使用SharedPreferences儲存資料 首先說明SharedPreferences儲存方式,它是Android提供的用來儲存一些簡單配置資訊的一種機制,例如:登入使用者的使用者名稱與密碼。其採用了Map資料結構來儲存資料,以索引值的方式儲存,可以簡單的讀取與寫入,具體執行個體如下: void ReadSharedPreferences() { String strName,strPassword; SharedPreferences user = getSharedPreferences(“user_info”,0); strName = user.getString(“NAME”,””); strPassword = user getString(“PASSWORD”,””); } void WriteSharedPreferences(String strName,String strPassword) { SharedPreferences user = getSharedPreferences(“user_info”,0); uer.edit(); user.putString(“NAME”, strName); user.putString(“PASSWORD” ,strPassword); user.commit(); } 資料讀取與寫入的方法都非常簡單,只是在寫入的時候有些區別:先調用edit()使其處於編輯狀態,然後才能修改資料,最後使用commit()提交修改的資料。實際上SharedPreferences是採用了XML格式將資料存放區到裝置中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的資料存放區結果為例,開啟後可以看到一個user_info.xml的檔案,開啟後可以看到: <?xml version=”1.0″ encoding=”UTF-8″?> <map> <string name=”NAME”>moandroid</string> <string name=” PASSWORD”>SharedPreferences</string> </map> 使用SharedPreferences是有些限制的:只能在同一個包內使用,不能在不同的包之間使用。 檔案儲存體資料 檔案儲存體方式是一種較常用的方法,在Android中讀取/寫入檔案的方法,與Java中實現I/O的程式是完全一樣的,提供了openFileInput()和openFileOutput()方法來讀取裝置上的檔案。FilterInputStream, FilterOutputStream等可以到Java io package說明中去詳細學習,不再此詳細說明,具體執行個體如下: String fn = “moandroid.log”; FileInputStream fis = openFileInput(fn); FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE); 除此之外,Android還提供了其他函數來操作檔案,詳細說明請閱讀Android SDK。 網路儲存資料 網路儲存方式,需要與Android 網路資料包打交道,關於Android 網路資料包的詳細說明,請閱讀Android SDK引用了Java SDK的哪些package?。 總結說明 以上5中儲存方式,在以後的開發過程中,根據設計目標、效能需求、空間需求等找到合適的資料存放區方式。Android 中的資料存放區都是私人的,其他應用程式都是無法訪問的,除非通過ContentResolver擷取其他程式共用的資料。 一、SQLite簡介 在Android平台上,整合了一個嵌入式關係型資料庫—SQLite,SQLite3支援 NULL、INTEGER、REAL(浮點數字)、TEXT(字串文本)和BLOB(二進位對象)資料類型,雖然它支援的類型雖然只有五種,但實際上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等資料類型,只不過在運算或儲存時會轉成對應的五種資料類型。 SQLite最大的特點是你可以儲存任何類型的資料到任何欄位中,無論這列聲明的資料類型是什麼。例如:可以在Integer欄位中存放字串,或者在布爾型欄位中存放浮點數,或者在字元型欄位中存放日期型值。 但有一種情況例外:定義為INTEGER PRIMARY KEY的欄位只能儲存64位整數, 當向這種欄位中儲存除整數以外的資料時,將會產生錯誤。另外, SQLite 在解析CREATE TABLE 語句時,會忽略 CREATE TABLE 語句中跟在欄位名後面的資料類型資訊。 二、SQLite的CURD Android提供了一個名為SQLiteDatabase的類,該類封裝了一些操作資料庫的API,使用該類可以完成對資料進行添加(Create)、查詢(Retrieve)、更新(Update)和刪除(Delete)操作(這些操作簡稱為CRUD)。對SQLiteDatabase的學習,我們應該重點掌握execSQL()和rawQuery()方法。 execSQL()方法可以執行insert、delete、update和CREATE TABLE之類有更改行為的SQL語句; rawQuery()方法可以執行select語句。SQLiteDatabase還專門提供了對應於添加、刪除、更新、查詢的操作方法:insert()、delete()、update()和query() 。這些方法實際上是給那些不太瞭解SQL文法的菜鳥使用的,對於熟悉SQL文法的程式員而言,直接使用execSQL()和rawQuery()方法執行SQL語句就能完成資料的添加、刪除、更新、查詢操作。 三、SQLite的交易管理 使用SQLiteDatabase的beginTransaction()方法可以開啟一個事務,程式執行到endTransaction() 方法時會檢查事務的標誌是否為成功,如果為成功則提交事務,否則復原事務。當應用需要提交事務,必須在程式執行到endTransaction()方法之前使用setTransactionSuccessful() 方法設定事務的標誌為成功,如果不調用setTransactionSuccessful() 方法,預設會復原事務。 三、SQLite建立、更新資料表 如果應用使用到了SQLite資料庫,在使用者初次使用軟體時,需要建立應用使用到的資料庫表結構及添加一些初始化記錄,另外在軟體升級的時候,也需要對資料表結構進行更新。在Android系統,為我們提供了一個名為SQLiteOpenHelper的類,該類用於對資料庫版本進行管理,該類是一個抽象類別,必須繼承它才能使用。為了實現對資料庫版本進行管理,SQLiteOpenHelper類有兩種重要的方法,分別是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 當調用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法擷取用於操作資料庫的SQLiteDatabase執行個體的時候,如果資料庫不存在,Android系統會自動產生一個資料庫,接著調用onCreate()方法,onCreate()方法在初次產生資料庫時才會被調用,在onCreate()方法裡可以產生資料庫表結構及添加一些應用使用到的初始化資料。onUpgrade()方法在資料庫的版本發生變化時會被調用,資料庫的版本是由程式員控制的,假設資料庫現在的版本是1,由於業務的需要,修改了資料庫表的結構,這時候就需要升級軟體,升級軟體時希望更新使用者手機裡的資料庫表結構,為了實現這一目的,可以把原來的資料庫版本設定為2(或其他數值),並且在onUpgrade()方法裡面實現表結構的更新。當軟體的版本升級次數比較多,這時在onUpgrade()方法裡面可以根據原版號和目標版本號碼進行判斷,然後作出相應的表結構及資料更新。 getWritableDatabase()和getReadableDatabase()方法都可以擷取一個用於操作資料庫的SQLiteDatabase執行個體。但getWritableDatabase() 方法以讀寫方式開啟資料庫,一旦資料庫的磁碟空間滿了,資料庫就只能讀而不能寫,倘若使用的是getWritableDatabase() 方法就會出錯。getReadableDatabase()方法先以讀寫方式開啟資料庫,如果資料庫的磁碟空間滿了,就會開啟失敗,當開啟失敗後會繼續嘗試以唯讀方式開啟資料庫。 |