Android中的跨進程通訊方法執行個體及特點分析(二):ContentProvider

來源:互聯網
上載者:User

Android中的跨進程通訊方法執行個體及特點分析(二):ContentProvider

1.ContentProvider簡介

在Android中有些資料(如通訊錄、音頻、視頻檔案等)是要供很多應用程式使用的,為了更好地對外提供資料,Android系統給我們提供了Content Provider使用,通過它可以訪問上面所說的資料,例如很多音樂播放器中的掃描功能其實就用到了Content Provider功能(當然,也有的播放器是自己去實現更底層的功能)。這樣的好處是統一管理,比如增加了某個音頻檔案,底層就會將這種變化通知Content Provider,從而當應用程式訪問時就可以獲得當前最新的資料。

當然,Android也允許我們定義自己的Content Provider,只要繼承它的基類,並且實現下面的方法即可。

public boolean onCreate() 在建立ContentProvider時調用
public Cursor query(Uri, String[], String, String[], String):用於查詢指定Uri的ContentProvider,返回一個Cursor
public Uri insert(Uri, ContentValues):根據指定的Uri添加資料到ContentProvider中
public int update(Uri, ContentValues, String, String[]):用於更新指定Uri的ContentProvider中的資料
public int delete(Uri, String, String[]):根據Uri刪除指定的資料
public String getType(Uri):用於返回指定的Uri中的資料的MIME類型
*如果操作的資料屬於集合類型,那麼MIME類型字串應該以vnd.android.cursor.dir/開頭。
例如:要得到所有p1記錄的Uri為content://contacts/p1,那麼返回的MIME類型字串為"vnd.android.cursor.dir/p1"。
*如果要操作的資料屬於非集合類型資料,那麼MIME類型字串應該以vnd.android.cursor.item/開頭。
例如:要得到id為100的student記錄的Uri為content://contacts/student/100,那麼返回的MIME類型字串應為"vnd.android.cursor.item/student"。

2.Uri簡介

一個標準的Uri為content://authority/path可分為以下三部分:

(1)content://:這個部分是ContentProvider規定的,就像http://代表Http這個協議一樣,使用ContentProvider的協議是content://

(2)authorities:它在所在的Android系統必須是唯一的,因為系統就是通過它來決定操作或訪問哪個ContentProvider的,這與互連網上的網址必須唯一是一樣的道理。

(3)path:資源路徑。

顯然,從上面的分析可以看出ContentProvider雖然也可實現跨進程通訊,但是它適用的情境主要是與資料庫相關,有時也可能是文字檔或XML等儲存方式。

3.ContentResolver

如果只是定義一個ContentProvider的話,沒有任何意義,因為ContentProvider只是內容提供者,它要被別的應用(進程)讀取才有價值。與實現ContentProvder的方法相對應,使用ContentResolver相關的方法如下所示:

getContentResolver():Context類提供的,用於擷取ContentResolver對象;

insert(Uri uri,ContentValues values):向Uri對應的ContentProvider中插入values對應的資料;

update(Uri uri,ContentValues values,String where,String[]selectionArgs):更新Uri對應的ContentProvider中where處的資料,其中selectionArgs是篩選參數;

query(Uri uri,String[]projection,String selection,String[]selectionArgs,String sortOrder):查詢Uri對應的ContentProvider中where處的資料,其中selectionArgs是篩選參數,sortOrder是排序方式;

delete(Uri uri,String where,String[]selectionArgs):刪除Uri對應的ContentProvider中where處的資料,其中selectionArgs是篩選參數;

4.UriMatcher

為了確定一個ContentProvider實際能處理的Uri,以及確定每個方法中Uri參數所操作的資料,Android系統提供了UriMatcher工具類。它主要有如下兩個方法:

(1)void addURI(String authority,String path,String code):該方法用於向UriMatcher對象註冊Uri。其中authority和path組合成一個Uri,而code則代表該Uri對應的標識碼;

(2)int match(Uri uri):根據前面註冊的Uri來判斷指定Uri對應的標識碼。如果找不到匹配的標識碼,該方法將會返回-1。

下面通過兩個執行個體來講解ContentProvider的用法,第一個執行個體是自己定義了一個ContentProvider並且在另一個應用中讀取它;第二個執行個體是讀取當前手機中的連絡人。

首先是第一個例子,項目結構如所示:


下面是各個類的代碼,首先是常量的定義:

package com.android.student.utils;import android.net.Uri;/** * 這裡定義了與ContentProvider相關的字串以及Student對應的資料表中的欄位 * @author Bettar * */public class StudentWords {//注意Manifest檔案中的authorities屬性要跟這裡保持一致。public static final String AUTHORITY="com.android.student.provider";public static final Uri STUDENT_WITH_ID_URI=Uri.parse("content://"+AUTHORITY+"/student");public static final Uri STUDENT_URI=Uri.parse("content://"+AUTHORITY+"/student");public static final String TABLE_NAME="student";public static final String ID="id";public static final String NAME="name";public static final String SCORE="score";public static final String ADDR="address";}
然後是資料庫協助類:

import com.android.student.utils.StudentWords;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.widget.Toast;public class StudentDbHelper extends SQLiteOpenHelper{private Context context;public StudentDbHelper(Context context,String name,int version){super(context,name,null,version);this.context=context;}@Overridepublic void onCreate(SQLiteDatabase db){String createSQL="create table "+StudentWords.TABLE_NAME+"("+StudentWords.ID+" integer primary key autoincrement,"+StudentWords.NAME+" varchar,"+StudentWords.SCORE+" integer,"+StudentWords.ADDR+" varchar)";db.execSQL(createSQL);}@Overridepublic void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){//升級版本時,可能要執行表結構的修改之類,此處暫時不考慮升級問題,因而只是用Toast提示Toast.makeText(context, "newVersion:"+newVersion+" will replace oldVersion:"+oldVersion,Toast.LENGTH_LONG).show();}}
最後是ContentProvider類的定義:

package com.android.student.provider;import com.android.student.database.StudentDbHelper;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri;import android.provider.UserDictionary.Words;import com.android.student.utils.StudentWords;public class StudentProvider extends ContentProvider{private static final String TAG="StudentProvider";private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);private static final int STUDENT_WITH_ID=1;    private static final int STUDENT=2;        private StudentDbHelper dbHelper;        static    {    matcher.addURI(StudentWords.AUTHORITY,"student/#",STUDENT_WITH_ID);    //matcher.addURI(StudentWords.AUTHORITY, "student", SINGLE_STUDENT);    //注意其中的#為萬用字元    matcher.addURI(StudentWords.AUTHORITY, "student", STUDENT);    }        @Override    public boolean onCreate()    {    dbHelper=new StudentDbHelper(this.getContext(),"student.db3",1);    return true;    }        @Override    public String getType(Uri uri)    {    switch(matcher.match(uri))    {    case STUDENT_WITH_ID:    return "vnd.android.cursor.item/com.android.student";    case STUDENT:    return "vnd.android.cursor.dir/com.android.student";    default:    throw new IllegalArgumentException("Unknown Uri:"+uri);    }    }        /**     * 由單一的selection這一個篩選條件組合成包含id的複雜篩選條件     * @param uri     * @param selection     * @return     */    private String getComplexSelection(Uri uri,String selection)    {    long id=ContentUris.parseId(uri);    String complexSelection=StudentWords.ID+"="+id;    if(selection!=null&&!"".equals(selection))    {    complexSelection+=" and "+selection;    }    return complexSelection;    }    @Overridepublic int delete(Uri uri,String selection,String[]selectionArgs) {SQLiteDatabase db=dbHelper.getReadableDatabase();int num=0;switch(matcher.match(uri)){case STUDENT_WITH_ID:String complexSelection=getComplexSelection(uri,selection);num=db.delete(StudentWords.TABLE_NAME, complexSelection, selectionArgs);break;case STUDENT:num=db.delete(StudentWords.TABLE_NAME,selection,selectionArgs);break;default:throw new IllegalArgumentException("Unknown Uri:"+uri);}//通知數據已經改變getContext().getContentResolver().notifyChange(uri, null);return num;}@Overridepublic Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db=dbHelper.getReadableDatabase();switch(matcher.match(uri)){     case STUDENT_WITH_ID:case STUDENT:long rowId=db.insert(StudentWords.TABLE_NAME, StudentWords.ID,values);if(rowId>0){Uri studentUri=ContentUris.withAppendedId(uri, rowId);//如果設定了觀察者的話,要通知所有觀察者getContext().getContentResolver().notifyChange(studentUri, null);return studentUri;}break;default:throw new IllegalArgumentException("Unknow Uri:"+uri);}    return null;}/** * 注意其中的projection其實是columns,即列名數組 */@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {SQLiteDatabase db=dbHelper.getReadableDatabase();switch(matcher.match(uri)){//這其實是包含id資訊的情況case STUDENT_WITH_ID:String complexSelection=getComplexSelection(uri,selection);return db.query(StudentWords.TABLE_NAME,projection,complexSelection,selectionArgs,null,null,sortOrder);//這是不帶數位情況,但是也未必就是好多個,一個也可以。case STUDENT:return db.query(StudentWords.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);default:throw new IllegalArgumentException("Unknow Uri"+uri);}}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {SQLiteDatabase db=dbHelper.getWritableDatabase();int num=0;switch(matcher.match(uri)){case STUDENT_WITH_ID:String complexSelection=getComplexSelection(uri,selection);num=db.update(StudentWords.TABLE_NAME, values, complexSelection, selectionArgs);break;case STUDENT:num=db.update(StudentWords.TABLE_NAME, values, selection,selectionArgs);break;default:throw new IllegalArgumentException("Unknow Uri:"+uri);}getContext().getContentResolver().notifyChange(uri,null);return num;}}
當然,要記得在Manifest檔案中加入ContentProvider的聲明:

 
下面是對ContentResolver的例子,首先項目中的檔案結構如下:



然後是layout檔案 :

<喎?"http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;"> 項目中也有StudentWords這個類,因為與上面的StudentWords完全相同,故此處不再列出,MainActivity的代碼如下:

package com.android.student.studentcontentresolver;import java.util.ArrayList;import java.util.List;import java.util.Map;import com.android.student.utils.StudentWords;import android.net.Uri;import android.os.Bundle;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.database.Cursor;import android.view.Menu;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import android.view.View;public class MainActivity extends Activity implements View.OnClickListener{ContentResolver contentResolver;private EditText nameET,scoreET,addressET;private Button insertButton;private EditText inputNameET;private Button searchButton;private EditText inputIdForUpdateET,inputIdForDeleteET;private Button updateButton,deleteButton;private void initView(){nameET=(EditText)findViewById(R.id.nameET);scoreET=(EditText)findViewById(R.id.scoreET);addressET=(EditText)findViewById(R.id.addrET);insertButton=(Button)findViewById(R.id.insertButton);inputNameET=(EditText)findViewById(R.id.inputNameET);searchButton=(Button)findViewById(R.id.searchButton);inputIdForUpdateET=(EditText)findViewById(R.id.inputIdET);inputIdForDeleteET=(EditText)findViewById(R.id.inputIdForDeleteET);updateButton=(Button)findViewById(R.id.updateButton);deleteButton=(Button)findViewById(R.id.deleteButton);insertButton.setOnClickListener(this);searchButton.setOnClickListener(this);updateButton.setOnClickListener(this);deleteButton.setOnClickListener(this);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);contentResolver=getContentResolver();initView();}@Overridepublic void onClick(View view){switch(view.getId()){case R.id.insertButton:insert();break;case R.id.searchButton:query();break;case R.id.updateButton:update();break;case R.id.deleteButton:delete();break;default:break;}}private void insert(){String name=nameET.getText().toString();String score=scoreET.getText().toString();String addr=addressET.getText().toString();ContentValues values=new ContentValues();values.put(StudentWords.NAME, name);values.put(StudentWords.SCORE, new Integer(score));values.put(StudentWords.ADDR, addr);//contentResolver.insert(StudentWords.SINGLE_STUDENT_URI, values);//一個是多個的特例,所以此處用MANY_STUDENTS_URI即可。contentResolver.insert(StudentWords.STUDENT_URI, values);       Toast.makeText(getBaseContext(), "新增學生資訊成功", Toast.LENGTH_SHORT).show();}private void query(){String name=inputNameET.getText().toString();//Cursor cursor=contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)Cursor cursor=contentResolver.query(StudentWords.STUDENT_URI, null, "name like ? or address like ?", new String[]{"%"+name+"%","%"+name+"%"}, null);Toast.makeText(getBaseContext(), getResult(cursor), Toast.LENGTH_LONG).show();}private void update(){//Uri updateUri=StudentWords.SINGLE_STUDENT_URI//更新id值為id的記錄Integer id=new Integer(inputIdForUpdateET.getText().toString());Uri updateUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI,id);ContentValues values=new ContentValues();values.put(StudentWords.NAME,"VictorWang");contentResolver.update(updateUri, values, null, null);}private void delete(){//刪除id值為id的記錄Integer id=new Integer(inputIdForDeleteET.getText().toString());Uri deleteUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI, id);contentResolver.delete(deleteUri, null, null);}private ListconvertCursor2List(Cursor cursor){    Listresult=new ArrayList();while(cursor.moveToNext()){result.add(cursor.getString(1)+"  ");result.add(cursor.getString(2)+"  ");result.add(cursor.getString(3)+"  ");}return result;}private String getResult(Cursor cursor){StringBuilder sb=new StringBuilder();while(cursor.moveToNext()){     sb.append(cursor.getString(1)+"  ");     sb.append(cursor.getString(2)+"  ");     sb.append(cursor.getString(3)+"\n");}return sb.toString();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}
運行結果如下:




今天先寫到這裡,連絡人和ContentObserver的例子後面再添加。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.