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"};@Overrideprotected 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 }));}@Overrideprotected 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);  }@Overridepublic 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());}}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}// ---------------------------------------------------------------------------------private DatabaseHelper mOpenHelper;@Overridepublic boolean onCreate() {mOpenHelper = new DatabaseHelper(getContext());  return true;  }@Overridepublic 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;}@Overridepublic String getType(Uri uri) {return null;  }@Overridepublic Uri insert(Uri uri, ContentValues initialValues) { return uri;}@Overridepublic int delete(Uri uri, String where, String[] whereArgs) { return 0; }@Overridepublic 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就会来启动它。


更多相关文章

  1. C语言函数以及函数的使用
  2. Android中Parcelable接口用法
  3. android执行外部程序,类似DELPHI里的EXEC函数
  4. Android对接webService接口
  5. 【面试】Android Retrofit+Rxjava 如何实现同时请求多个接口数据
  6. [Android Studio] Android Studio如何提示函数用法
  7. Android 驱动之旅 第四章:在Android 系统中编写JNI 方法在应用程
  8. 一种绕过Android P对非SDK接口限制的简单方法
  9. Android笔记:Android后台接口教程一(从零开始学习Android后台接口)A

随机推荐

  1. Android读写XML(下)——创建XML文档
  2. osmdroid的使用
  3. 浅谈android的selector背景选择器
  4. Android(安卓)Toast优化,不看别后悔
  5. 对Android进程优先级和Service的理解
  6. 解决TextView中MaxLines与ellipsize=end
  7. Android的多媒体数据库
  8. [Android]自定义View带效果的滚动数字
  9. Android应用安装错误:INSTALL_FAILED_MEDI
  10. Android应用程序资源——Drawable资源概