馬上加入Android 台灣中文網,立即免費下載應用遊戲。
您需要 登錄 才可以下載或查看,沒有帳號?註冊
x
1. 何謂Android的嫡系組件
Android有4項一等公民(或稱為嫡系親屬),包括:Activity、ContentProvider、IntentReceiver與Service。它們都必須宣告於AndroidManifest.xml檔案裡,如下:- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.misoo.SQ03">
- <uses-permission xmlns:android="http://schemas.android.com/apk/res/android"
- android:name="android.permission.INTERNET">
- </uses-permission>
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <provider android:name="DataProvider"
- android:authorities="com.misoo.provider.SQ03">
- </provider>
- <activity android:name=".ac01" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".DispActivity" android:label="DispActivity">
- </activity>
- </application>
- </manifest>
複製代碼 這讓Android知道我們城市裡定義了多少個嫡系組件類別;Android可以在啟動時就將它們執行起來,成為共享的(Shared)服務組件。這些嫡系服務組件間的溝通,通常是透過「意圖」(Intent)對像來請Android轉達給對方,Android則會依據意圖而找出最佳的配對。配對成功,就展開相互的溝通與服務了。
2. 什麼是ContentProvider嫡系組件
---- 以SQLite為例
在Android裡,SQLite數據庫是最典型的ContentProvider,負責儲存各式各樣的內容。除了數據庫之外,還有許多其它種類的ContentProvider。在這裡並不是要介紹這些ContentProvider,而是要透過SQLite認識ContentProvider接口,然後將舶來Linter組件,配上這種ContentProvider接口,讓它搖身一變成為Android的嫡系組件。
2.1 一般(即非嫡系)SQLite的範例
沒有透過ContentProvider接口來使用SQLite,就是對SQLite的「非嫡系」用法。此時,應用程式透過JDBC接口和SQL語句來與SQLite溝通,以存取數據庫裡的內容。先認識這種傳統用法。此範例將從SQLite讀取數據。首先建立一個程式項目,其含有兩個Java程式文件:ac01.java和DataProvider.java。其中,ac01.java 是典型的Activity類別,負責UI畫面的顯示工作,而DataProvider則負責與SQLite溝通。其詳細程式代碼為:- /* ----- ac01.java 程式代碼 ------*/
- package com.misoo.pklx;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- import android.app.ListActivity;
- import android.database.Cursor;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ListView;
- import android.widget.SimpleAdapter;
- public class ac01 extends ListActivity {
- private static final String[] PROJECTION = new String[] { "stud_no", "stud_name" };
- @Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- DataProvider dp = new DataProvider(this);
- Cursor cur = dp.query(PROJECTION, null, null, null);
- ArrayList<Map<String, Object>> coll
- = new ArrayList<Map<String, Object>>();
- Map<String, Object> item;
- cur.moveToFirst();
- while(!cur.isAfterLast()) {
- item = new HashMap<String, Object>();
- item.put("c1", cur.getString(0) + ", " + cur.getString(1));
- coll.add(item);
- cur.moveToNext();
- }
- dp.close();
- this.setListAdapter(new SimpleAdapter(this, coll,
- android.R.layout.simple_list_item_1, new String[] { "c1" },
- new int[] {android.R.id.text1}));
- }
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- finish();
- }}
複製代碼 指令:- DataProvider dp = new DataProvider(this);
複製代碼 這和一般類別之用法是一樣的。ac01對像指名要誕生一個DataProvider的物件。然後呼叫它,如下指令:
Cursor cur = dp.query(PROJECTION, null, null, null);
這要求SQLite從數據庫查詢出某些數據。詳細的DataProvider.java程式代碼如下:- /* ----- DataProvider.java 程式代碼 ------*/
- package com.misoo.pklx;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.SQLException;
- import android.database.sqlite.SQLiteDatabase;
- import android.util.Log;
- public class DataProvider {
- private static final String DATABASE_NAME = "StudDB";
- private static final String TABLE_NAME = "Student";
- private final int DB_MODE = Context.MODE_PRIVATE;
- private SQLiteDatabase db=null;
-
- public DataProvider(Context ctx) {
- try { db = ctx.openOrCreateDatabase(DATABASE_NAME, DB_MODE, null); }
- catch (Exception e) { Log.e("ERROR", e.toString()); return; }
-
- try { db.execSQL("drop table "+ TABLE_NAME); }
- catch (Exception e) { Log.e("ERROR", e.toString()); }
-
- db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "stud_no" + " TEXT,"
- + "stud_name" + " TEXT" + ");");
- String sql_1 = "insert into "+ TABLE_NAME +
- " (stud_no, stud_name) values('S101', 'Lily');";
- String sql_2 = "insert into " + TABLE_NAME +
- " (stud_no, stud_name) values('S102', 'Linda');";
- String sql_3 = "insert into " + TABLE_NAME +
- " (stud_no, stud_name) values('S103', 'Bruce');";
-
- try { db.execSQL(sql_1); db.execSQL(sql_2); db.execSQL(sql_3); }
- catch (SQLException e) { Log.e("ERROR", e.toString()); return; }
- }
- public Cursor query(String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- Cursor cur = db.query(TABLE_NAME, projection, null, null, null, null, null);
- return cur;
- }
- public void close(){ db.close(); }
- }
複製代碼 這種用法屬於非嫡系的用法:在ac01.java程式代碼裡,其指令:- DataProvider dp = new DataProvider(this);
複製代碼 明確指定由DataProvider對像來提供服務。反之,嫡系用法則是透過意圖(Intent)來請Android代為配對,進而找出適當的ContentProvider對像來為aco1對像提供服務。
2.2 嫡系SQLite的範例
剛才的範例裡,我們直接使用DataProvider類別的接口來與SQLite溝通。本節的範例,將替DataProvider配上ContentProvider接口,讓ac01對像能透過ContentProvider新接口來溝通。此範例也是從SQLite數據庫讀取3筆數據;請仔細看看其程式代碼的微妙差異:- /* ----- ac01.java 程式代碼 ------*/
- package com.misoo.pkrr;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- import android.app.ListActivity;
- import android.content.Intent;
- import android.database.Cursor;
- import android.net.Uri;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ListView;
- import android.widget.SimpleAdapter;
- public class ac01 extends ListActivity {
- public static int g_variable;
- public static final String AUTHORITY = "com.misoo.provider.rx09-02";
- public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
- + "/Student");
- private static final String[] PROJECTION
- = new String[]{ "stud_no", "stud_name"};
- @Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Intent intent = getIntent();
- if (intent.getData() == null) intent.setData(CONTENT_URI);
- Cursor cur = getContentResolver().query(getIntent().getData(),
- PROJECTION, null, null, null);
- ArrayList<Map<String, Object>> coll = new ArrayList<Map<String, Object>>();
- Map<String, Object> item;
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- item = new HashMap<String, Object>();
- item.put("c1", cur.getString(0) + ", " + cur.getString(1));
- coll.add(item);
- cur.moveToNext();
- }
- this.setListAdapter(new SimpleAdapter(this, coll,
- android.R.layout.simple_list_item_1, new String[] { "c1" },
- new int[] { android.R.id.text1 }));
- }
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) { finish();}
- }
複製代碼 指令:- Cursor cur = getContentResolver().query(getIntent().getData(),
- PROJECTION, null, null, null);
複製代碼 要求Android代為尋找適合的ContentProvider來提供服務,並不刻意指定由DataProvider對像來擔任。只要合乎ConentProvider接口,且符合意圖條件的對象皆可以來為ac01對像提供服務。於是,ac01程式代碼就不再直接呼叫DataProvider類別的函數了,而是呼叫ContentProvider接口所提供的函數。再來仔細看看DataProvider類別與ContentProvider接口的搭配情形:- /* ----- DataProvider.java 程式代碼 ------*/
- package com.misoo.pkrr;
- import android.content.ContentProvider;
- import android.content.ContentValues;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.SQLException;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import android.net.Uri;
- import android.util.Log;
- public class DataProvider extends ContentProvider {
- private static final String DATABASE_NAME = "StudNewDB";
- private static final int DATABASE_VERSION = 2;
- private static final String TABLE_NAME = "StudTable";
- private static class DatabaseHelper extends SQLiteOpenHelper {
- DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION); }
- @Override public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "stud_no"
- + " TEXT," + "stud_name" + " TEXT" + ");");
- String sql_1 = "insert into " + TABLE_NAME
- + " (stud_no, stud_name) values('S1001', 'Pam');";
- String sql_2 = "insert into " + TABLE_NAME
- + " (stud_no, stud_name) values('S1002', 'Steve');";
- String sql_3 = "insert into " + TABLE_NAME
- + " (stud_no, stud_name) values('S1003', 'John');";
- try { db.execSQL(sql_1); db.execSQL(sql_2); db.execSQL(sql_3); }
- catch (SQLException e) { Log.e("ERROR", e.toString()); }
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
- }
- // ---------------------------------------------------------------------------------
- private DatabaseHelper mOpenHelper;
- @Override public boolean onCreate() {
- mOpenHelper = new DatabaseHelper(getContext()); return true; }
- @Override public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor c = db.query(TABLE_NAME, projection, null, null, null, null, null);
- return c;
- }
- @Override public String getType(Uri uri) { return null; }
- @Override public Uri insert(Uri uri, ContentValues initialValues) { return uri; }
- @Override public int delete(Uri uri, String where, String[] whereArgs) { return 0; }
- @Override public int update(Uri uri, ContentValues values, String where,
- String[] whereArgs)
- { return 0; }
- }
複製代碼 類別定義:- public class DataProvider extends ContentProvider {
- // …..…..
- }
複製代碼 DataProvider類別繼承ContentProvider父類別,也繼承了它的接口定義。ContentProvider接口定義了多個函數,主要包括:
l query()函數---- 它查詢出合乎某條件的數據。
l insert()函數---- 它將存入一筆新資料。
l delete()函數---- 它刪除合乎某條件的資料。
l update()函數---- 更新某些筆數據的內容。
在這個DataProvider類別裡,撰寫了query()函數內的指令,來實現query()接口,這個query()函數實際呼叫SQLite數據庫的功能。也就是說,ac01等應用程式透過ContentProvider接口間接呼叫到DataProvider的query()函數,然後此query()函數才使用SQLite的服務。
由於此範例的DataProvider已經是ContentProvider嫡系身份了,必須由Android來啟動它,而不是有ac01等應用程式來直接啟動它,所以必須在AndroidManifest.xml文檔裡給Android一些指示,如下:- /* ----- AndroidManifest.xml 文檔 ------*/
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.misoo.pkrr"
- android:versionCode="1"
- android:versionName="1.0.0">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".ac01"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <provider android:name="DataProvider"
- android:authorities="com.misoo.provider.rx09-02">
- </provider>
- </application>
- </manifest>
複製代碼 這特別說明DataProvider是一個ContentProvider,於是Android就會來啟動它。 |
評分
-
查看全部評分
|