1、2.高焕堂讲解 ContentProvider 范例1. 何谓 Android 的嫡系组件Android 有 4 项 一 等 公 民 (或 称 为 嫡 系 亲 属 ),包 括 :Activity、ContentProvider、IntentReceiver 与 Service。它 们 都 必 须 宣 告 于 AndroidManifest.xml档 案 里 ,如 下 :这 让 Android 知 道 我 们 城 市 里 定 义 了 多 少 个 嫡 系 组 件 类 别 ;Android 可 以 在 启 动 时 就 将它 们 执 行 起 来 ,成 为 共 享 的 (Shared)服 务 组 件 。
2、这 些 嫡 系 服 务 组 件 间 的 沟 通 ,通 常 是 透 过 意图 (Intent)对 象 来 请 Android 转 达 给 对 方 ,Android 则 会 依 据 意 图 而 找 出 最 佳 的 配 对 。配 对 成功 ,就 展 开 相 互 的 沟 通 与 服 务 了 。2. 什么是 ContentProvider 嫡系组件- 以 SQLite 为 例在 Android 里 ,SQLite 数 据 库 是 最 典 型 的 ContentProvider,负 责 储 存 各 式 各 样 的 内 容 。除 了 数 据 库 之 外 ,还 有 许 多 其 它 种 类 的 ContentP
3、rovider。在 这 里 并 不 是 要 介 绍 这 些ContentProvider,而 是 要 透 过 SQLite 认 识 ContentProvider 接 口 ,然 后 将 舶 来 Linter 组 件 ,配上 这 种 ContentProvider 接 口 ,让 它 摇 身 一 变 成 为 Android 的 嫡 系 组 件 。2.1 一 般 (即 非 嫡 系 )SQLite 的 范 例没 有 透 过 ContentProvider 接 口 来 使 用 SQLite,就 是 对 SQLite 的 非 嫡 系 用 法 。此 时 ,应 用 程 序 透 过 JDBC 接 口 和 SQL
4、 语 句 来 与 SQLite 沟 通 ,以 存 取 数 据 库 里 的 内 容 。先 认 识 这种 传 统 用 法 。此 范 例 将 从 SQLite 读 取 数 据 。首 先 建 立 一 个 程 序 项 目 ,其 含 有 两 个 Java 程 序 文件 :ac01.java 和 DataProvider.java。其 中 ,ac01.java 是 典 型 的 Activity 类 别 ,负 责 UI 画 面 的 显示 工 作 ,而 DataProvider 则 负 责 与 SQLite 沟 通 。其 详 细 程 序 代 码 为 :/* - ac01.java 程 序 代 码 -*/pack
5、age 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 Li
6、stActivity 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 coll= new Array
7、List();Map item; cur.moveToFirst();while(!cur.isAfterLast() item = new HashMap();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
8、.R.id.text1);Overrideprotected 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);这 要 求 SQL
9、ite 从 数 据 库 查 询 出 某 些 数 据 。详 细 的 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 cla
10、ss 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); ca
11、tch (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_
12、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)
13、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 程 序 代 码 里
14、,其 指 令 :DataProvider dp = new DataProvider(this);明 确 指 定 由 DataProvider 对 象 来 提 供 服 务 。反 之 ,嫡 系 用 法 则 是 透 过 意 图 (Intent)来 请 Android代 为 配 对 ,进 而 找 出 适 当 的 ContentProvider 对 象 来 为 aco1 对 象 提 供 服 务 。2.2 嫡 系 SQLite 的 范 例刚 才 的 范 例 里 ,我 们 直 接 使 用 DataProvider 类 别 的 接 口 来 与 SQLite 沟 通 。本 节 的 范 例 ,将 替 DataP
15、rovider 配 上 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
16、;import android.content.Intent;import android.database.Cursor;import .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 = “c
17、om.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 = ge
18、tIntent();if (intent.getData() = null) intent.setData(CONTENT_URI);Cursor cur = getContentResolver().query(getIntent().getData(),PROJECTION, null, null, null);ArrayList coll = new ArrayList();Map item;cur.moveToFirst();while (!cur.isAfterLast() item = new HashMap();item.put(“c1“, cur.getString(0) +
19、“, “ + 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 );Overrideprotected void onListItemClick(ListView l, View v, int position, long id) finish();指 令 :Cursor cur = get
20、ContentResolver().query(getIntent().getData(),PROJECTION, null, null, null);要 求 Android 代 为 寻 找 适 合 的 ContentProvider 来 提 供 服 务 ,并 不 刻 意 指 定 由 DataProvider 对象 来 担 任 。只 要 合 乎 ConentProvider 接 口 ,且 符 合 意 图 条 件 的 对 象 皆 可 以 来 为 ac01 对 象 提 供服 务 。于 是 ,ac01 程 序 代 码 就 不 再 直 接 呼 叫 DataProvider 类 别 的 函 数 了 ,而
21、 是 呼 叫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;impor
22、t android.database.SQLException;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import .Uri;import android.util.Log;public class DataProvider extends ContentProvider private static final String DATABASE_NAME = “StudNewDB“;private static final int DATABAS
23、E_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_N
24、AME + “ (“ + “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, s
25、tud_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(); Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) / -private DatabaseHelper mOpenHelper;Override public boolean onCreate() m
26、OpenHelper = 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)
27、;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 where
28、Args) return 0; 类 别 定 义 :public class DataProvider extends ContentProvider / DataProvider 类 别 继 承 ContentProvider 父 类 别 ,也 继 承 了 它 的 接 口 定 义 。ContentProvider 接口 定 义 了 多 个 函 数 ,主 要 包 括 :l query()函 数 - 它 查 询 出 合 乎 某 条 件 的 数 据 。l insert()函 数 - 它 将 存 入 一 笔 新 资 料 。l delete()函 数 - 它 删 除 合 乎 某 条 件 的 资 料 。l
29、 update()函 数 - 更 新 某 些 笔 数 据 的 内 容 。在 这 个 DataProvider 类 别 里 ,撰 写 了 query()函 数 内 的 指 令 ,来 实 现 query()接 口 ,这 个query()函 数 实 际 呼 叫 SQLite 数 据 库 的 功 能 。也 就 是 说 ,ac01 等 应 用 程 序 透 过 ContentProvider接 口 间 接 呼 叫 到 DataProvider 的 query()函 数 ,然 后 此 query()函 数 才 使 用 SQLite 的 服 务 。由 于 此 范 例 的 DataProvider 已 经 是 ContentProvider 嫡 系 身 份 了 ,必 须 由 Android 来 启动 它 ,而 不 是 有 ac01 等 应 用 程 序 来 直 接 启 动 它 ,所 以 必 须 在 AndroidManifest.xml 文 档 里 给Android 一 些 指 示 ,如 下 :/* - AndroidManifest.xml 文 檔 -*/这 特 别 说 明 DataProvider 是 一 个 ContentProvider,于 是 Android 就 会 来 启 动 它 。