Chinaunix首页 | 论坛 | 博客
  • 博客访问: 842298
  • 博文数量: 244
  • 博客积分: 10000
  • 博客等级: 上将
  • 技术积分: 2420
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-29 09:07
文章分类

全部博文(244)

文章存档

2011年(4)

2010年(3)

2009年(72)

2008年(119)

2007年(46)

我的朋友

分类: LINUX

2009-03-25 22:56:42

1.  何謂Android的嫡系組件       Android有4項一等公民(或稱為嫡系親屬),包括:Activity、ContentProvider、IntentReceiver與Service。它們都必須宣告於AndroidManifest.xml檔案裡,如下:     

1.  何謂Android的嫡系組件

 

    Android4項一等公民(或稱為嫡系親屬),包括:ActivityContentProviderIntentReceiverService。它們都必須宣告於AndroidManifest.xml檔案裡,如下:

 

    package="com.misoo.SQ03">

     

         android:name="android.permission.INTERNET">

   

   

        <provider android:name="DataProvider"

            android:authorities="com.misoo.provider.SQ03">

        provider>

        <activity android:name=".ac01" android:label="@string/app_name">

           

               

               

           

        activity>

        <activity android:name=".DispActivity" android:label="DispActivity">

        activity>

   

 

    這讓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.javaDataProvider.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> coll

                = new ArrayList>();

        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.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> coll = new ArrayList>();

                     Map item;

                     cur.moveToFirst();

                     while (!cur.isAfterLast()) {

                                item = new HashMap();

                                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介面間接呼叫到DataProviderquery()函數,然後此query()函數才使用SQLite的服務。

     由於此範例的DataProvider已經是ContentProvider嫡系身份了,必須由Android來啟動它,而不是有ac01等應用程式來直接啟動它,所以必須在AndroidManifest.xml文檔裡給Android一些指示,如下:

 

/* ----- AndroidManifest.xml 文檔 ------*/

      package="com.misoo.pkrr"

      android:versionCode="1"

      android:versionName="1.0.0">

   

       

                  android:label="@string/app_name">

           

               

               

           

       

       

            android:authorities="com.misoo.provider.rx09-02">

       

   

 

這特別說明DataProvider是一個ContentProvider,於是Android就會來啟動它。

  (by Misoo團隊)

阅读(565) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~