高焕堂讲义之二:ContentProvider…

高焕堂讲义之二:ContentProvider范例
1. 何谓Android的嫡系组件

    Android有4项一等公民(或称为嫡系亲属),包括:Activity、ContentProvider、IntentReceiver与Service。它们都必须宣告于AndroidManifest.xml档案里,如下:

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.misoo.SQ03">  
  4.     <uses-permission xmlns:android="http://schemas.android.com/apk/res/android"     
  5.          android:name="android.permission.INTERNET">  
  6.     </uses-permission>  
  7.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  8.         <provider android:name="DataProvider"  
  9.             android:authorities="com.misoo.provider.SQ03">  
  10.         </provider>  
  11.         <activity android:name=".ac01" android:label="@string/app_name">  
  12.             <intent-filter>  
  13.                 <action android:name="android.intent.action.MAIN" />  
  14.                 <category android:name="android.intent.category.LAUNCHER" />  
  15.             </intent-filter>  
  16.         </activity>  
  17.         <activity android:name=".DispActivity" android:label="DispActivity">  
  18.         </activity>  
  19.     </application>  
  20. </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沟通。其详细程序代码为:
 

Java代码
  1. package com.misoo.pklx;   
  2. import java.util.ArrayList;   
  3. import java.util.HashMap;   
  4. import java.util.Map;   
  5. import android.app.ListActivity;   
  6. import android.database.Cursor;   
  7. import android.os.Bundle;   
  8. import android.view.View;   
  9. import android.widget.ListView;   
  10. import android.widget.SimpleAdapter;   
  11.   
  12. public class ac01 extends ListActivity {   
  13.     private static final String[] PROJECTION new String[] "stud_no""stud_name" };   
  14.   
  15.     @Override protected void onCreate(Bundle savedInstanceState) {   
  16.        super.onCreate(savedInstanceState);   
  17.         DataProvider dp new DataProvider(this);   
  18.         Cursor cur dp.query(PROJECTION, nullnullnull);   
  19.         ArrayList<Map<String, Object>> coll   
  20.                 new ArrayList<Map<String, Object>>();   
  21.         Map<String, Object> item;    
  22.         cur.moveToFirst();   
  23.         while(!cur.isAfterLast()) {   
  24.           item new HashMap<String, Object>();   
  25.           item.put("c1"cur.getString(0) ",  " cur.getString(1));   
  26.           coll.add(item);   
  27.           cur.moveToNext();   
  28.         }   
  29.         dp.close();   
  30.         this.setListAdapter(new SimpleAdapter(thiscoll,   
  31.               android.R.layout.simple_list_item_1, new String[] "c1" },   
  32.               new int[] {android.R.id.text1}));   
  33.     }   
  34.     @Override  
  35.     protected void onListItemClick(ListView l, View v, int position, long id) {   
  36.         finish();   
  37.  }}   

 指令:
           DataProvider dp = new DataProvider(this);

     这和一般类别之用法是一样的。ac01对象指名要诞生一个DataProvider的物件。然后呼叫它,如下指令:
          Cursor cur = dp.query(PROJECTION, null, null, null);

这要求SQLite从数据库查询出某些数据。详细的DataProvider.java程序代码如下:


Java代码
  1. package com.misoo.pklx;   
  2. import android.content.Context;   
  3. import android.database.Cursor;   
  4. import android.database.SQLException;   
  5. import android.database.sqlite.SQLiteDatabase;   
  6. import android.util.Log;   
  7.   
  8. public class DataProvider {   
  9.     private static final String DATABASE_NAME "StudDB";   
  10.     private static final String TABLE_NAME "Student";   
  11.     private final int DB_MODE Context.MODE_PRIVATE;   
  12.     private SQLiteDatabase db=null;   
  13.         
  14.     public DataProvider(Context ctx) {   
  15.        try  db ctx.openOrCreateDatabase(DATABASE_NAME, DB_MODE, null);   }   
  16. catch (Exception e)  Log.e("ERROR"e.toString());   return  }   
  17.   
  18.        try db.execSQL("drop table "TABLE_NAME); }   
  19. catch (Exception e)  Log.e("ERROR"e.toString());   }   
  20.   
  21.        db.execSQL("CREATE TABLE " TABLE_NAME ("  "stud_no" TEXT,"  
  22.                         "stud_name" TEXT" ");");   
  23.       String sql_1 "insert into "TABLE_NAME    
  24. (stud_no, stud_name) values('S101', 'Lily');";   
  25.  String sql_2 "insert into " TABLE_NAME    
  26. (stud_no, stud_name) values('S102', 'Linda');";   
  27.       String sql_3 "insert into " TABLE_NAME    
  28. (stud_no, stud_name) values('S103', 'Bruce');";   
  29.   
  30.    try  db.execSQL(sql_1);   db.execSQL(sql_2);  db.execSQL(sql_3); }   
  31.  catch (SQLException e)  Log.e("ERROR"e.toString());  return }   
  32.    }   
  33.     public Cursor query(String[] projection, String selection, String[] selectionArgs,    
  34.                     String sortOrder) {   
  35.        Cursor cur db.query(TABLE_NAME, projection, nullnullnullnullnull);   
  36.            return cur;   
  37.     }   
  38.     public void close(){   db.close();   }   
  39. }   

这种用法属于非嫡系的用法:在ac01.java程序代码里,其指令:
           DataProvider dp = new DataProvider(this);

明确指定由DataProvider对象来提供服务。反之,嫡系用法则是透过意图(Intent)来请Android代为配对,进而找出适当的ContentProvider对象来为aco1对象提供服务。


2.2  嫡系SQLite的范例

    刚才的范例里,我们直接使用DataProvider类别的接口来与SQLite沟通。本节的范例,将替DataProvider配上ContentProvider接口,让ac01对象能透过ContentProvider新接口来沟通。此范例也是从SQLite数据库读取3笔数据;请仔细看看其程序代码的微妙差异:

 

Java代码
  1. package com.misoo.pkrr;   
  2. import java.util.ArrayList;   
  3. import java.util.HashMap;   
  4. import java.util.Map;   
  5. import android.app.ListActivity;   
  6. import android.content.Intent;   
  7. import android.database.Cursor;   
  8. import android.net.Uri;   
  9. import android.os.Bundle;   
  10. import android.view.View;   
  11. import android.widget.ListView;   
  12. import android.widget.SimpleAdapter;   
  13.   
  14. public class ac01 extends ListActivity {   
  15.     public static int g_variable;   
  16.     public static final String AUTHORITY "com.misoo.provider.rx09-02";   
  17.     public static final Uri CONTENT_URI Uri.parse("content://" AUTHORITY   
  18.             "/Student");   
  19.     private static final String[] PROJECTION    
  20.               new String[]{ "stud_no""stud_name"};   
  21.     @Override   protected void onCreate(Bundle savedInstanceState) {   
  22.         super.onCreate(savedInstanceState);   
  23.         Intent intent getIntent();   
  24.         if (intent.getData() == null intent.setData(CONTENT_URI);   
  25.         Cursor cur getContentResolver().query(getIntent().getData(),   
  26.                 PROJECTION, nullnullnull);   
  27.         ArrayList<Map<String, Object>> coll new ArrayList<Map<String, Object>>();   
  28.         Map<String, Object> item;   
  29.         cur.moveToFirst();   
  30.         while (!cur.isAfterLast()) {   
  31.             item new HashMap<String, Object>();   
  32.             item.put("c1"cur.getString(0) ",  " cur.getString(1));   
  33.             coll.add(item);   
  34.             cur.moveToNext();   
  35.         }   
  36.         this.setListAdapter(new SimpleAdapter(thiscoll,   
  37.                 android.R.layout.simple_list_item_1, new String[] "c1" },   
  38.                 new int[] android.R.id.text1 }));   
  39.     }   
  40.     @Override  
  41.     protected void onListItemClick(ListView l, View v, int position, long id) finish();}   
  42. }   

指令:
              Cursor cur = getContentResolver().query(getIntent().getData(),
              PROJECTION, null, null, null);

要求Android代为寻找适合的ContentProvider来提供服务,并不刻意指定由DataProvider对象来担任。只要合乎ConentProvider接口,且符合意图条件的对象皆可以来为ac01对象提供服务。于是,ac01程序代码就不再直接呼叫DataProvider类别的函数了,而是呼叫ContentProvider接口所提供的函数。再来仔细看看DataProvider类别与ContentProvider接口的搭配情形:


Java代码
  1. package com.misoo.pkrr;   
  2. import android.content.ContentProvider;   
  3. import android.content.ContentValues;   
  4. import android.content.Context;   
  5. import android.database.Cursor;   
  6. import android.database.SQLException;   
  7. import android.database.sqlite.SQLiteDatabase;   
  8. import android.database.sqlite.SQLiteOpenHelper;   
  9. import android.net.Uri;   
  10. import android.util.Log;   
  11.   
  12. public class DataProvider extends ContentProvider {   
  13.     private static final String DATABASE_NAME "StudNewDB";   
  14.     private static final int DATABASE_VERSION 2;   
  15.     private static final String TABLE_NAME "StudTable";   
  16.     private static class DatabaseHelper extends SQLiteOpenHelper {   
  17.         DatabaseHelper(Context context) {   
  18.             super(context, DATABASE_NAME, nullDATABASE_VERSION);  }   
  19.         @Override   public void onCreate(SQLiteDatabase db) {   
  20.             db.execSQL("CREATE TABLE " TABLE_NAME (" "stud_no"  
  21.                     TEXT," "stud_name" TEXT" ");");   
  22.             String sql_1 "insert into " TABLE_NAME   
  23.                     (stud_no, stud_name) values('S1001', 'Pam');";   
  24.             String sql_2 "insert into " TABLE_NAME   
  25.                     (stud_no, stud_name) values('S1002', 'Steve');";   
  26.             String sql_3 "insert into " TABLE_NAME   
  27.                     (stud_no, stud_name) values('S1003', 'John');";   
  28.             try db.execSQL(sql_1);  db.execSQL(sql_2);  db.execSQL(sql_3);    }   
  29.  catch (SQLException e) Log.e("ERROR"e.toString()); }   
  30.         }   
  31.         @Override  
  32.         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}   
  33.     }   
  34.     // ---------------------------------------------------------------------------------   
  35.     private DatabaseHelper mOpenHelper;   
  36.     @Override   public boolean onCreate() {   
  37.         mOpenHelper new DatabaseHelper(getContext());  return true }   
  38.     @Override   public Cursor query(Uri uri, String[] projection, String selection,   
  39.             String[] selectionArgs, String sortOrder) {   
  40.         SQLiteDatabase db mOpenHelper.getReadableDatabase();   
  41.         Cursor db.query(TABLE_NAME, projection, nullnullnullnullnull);   
  42.         return c;   
  43.     }   
  44.     @Override   public String getType(Uri uri)    return null }   
  45.     @Override   public Uri insert(Uri uri, ContentValues initialValues) return uri;   }   
  46.     @Override   public int delete(Uri uri, String where, String[] whereArgs) return 0; }   
  47.     @Override   public int update(Uri uri, ContentValues values, String where,   
  48.             String[] whereArgs)    
  49.  return 0;  }   
  50. }   

类别定义:
           public class DataProvider extends ContentProvider {
// …..…..
}

DataProvider类别继承ContentProvider父类别,也继承了它的接口定义。ContentProvider接口定义了多个函数,主要包括:
          query()函数---- 它查询出合乎某条件的数据。
          insert()函数---- 它将存入一笔新资料。
          delete()函数---- 它删除合乎某条件的资料。
          update()函数---- 更新某些笔数据的内容。

     在这个DataProvider类别里,撰写了query()函数内的指令,来实现query()接口,这个query()函数实际呼叫SQLite数据库的功能。也就是说,ac01等应用程序透过ContentProvider接口间接呼叫到DataProvider的query()函数,然后此query()函数才使用SQLite的服务。
     由于此范例的DataProvider已经是ContentProvider嫡系身份了,必须由Android来启动它,而不是有ac01等应用程序来直接启动它,所以必须在AndroidManifest.xml文档里给Android一些指示,如下:


XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.misoo.pkrr"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0.0">  
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.         <activity android:name=".ac01"  
  8.                   android:label="@string/app_name">  
  9.             <intent-filter>  
  10.                 <action android:name="android.intent.action.MAIN" />  
  11.                 <category android:name="android.intent.category.LAUNCHER" />  
  12.             </intent-filter>  
  13.         </activity>  
  14.         <provider android:name="DataProvider"  
  15.             android:authorities="com.misoo.provider.rx09-02">  
  16.         </provider>  
  17.     </application>  
  18. </manifest>  

这特别说明DataProvider是一个ContentProvider,于是Android就会来启动它。

 

转至:http://dev.10086.cn/cmdn/wiki/index.php?edition-view-2609-2.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值