自定義ContentProvider
來源:程序員人生 發布時間:2016-11-19 14:52:14 閱讀次數:2691次
當多個利用程序同享同1數據時,我們可以給這個數據定義1個URI,然后把這個URI以接口的情勢暴漏出去,以后其他利用程序對此數據進行增刪改查時,只需要從當前上下文對象取得1個ContentResolver(內容解析器)傳入相應的URI就能夠了。數據庫支持直接操作db文件,問甚么還要用內容提供人?這是出于安全的斟酌,內容提供者可以根據自己的意愿選擇性的提供數據給客戶端使用。
(1)、操作步驟:
1、編寫1個類,讓其繼承自ContentProvider類;
2、實現ContentProvider類中所有的抽象方法;需要實現:onCreate()
、getType() 、query()
、insert() 、update()、delete()
等方法。
3、定義ContentProvider的Uri。這個Uri是ContentResolver對象履行CRUD操作時重要的參數;
4、使用UriMatcher對象映照Uri返回代碼;
5、在AndroidMainfest.xml文件中使用<provider>標簽注冊ContentProvider。
備注:
ContentProvider暴露出來的數據和方法其實不是給本身調用的,而是給其他利用程序來調用。其他利用程序通過其ContentResolver對象調用的query() 、insert()
、update()、delete() 等方法就是我們在這里暴露出來的ContentProvider類中的重寫后的query()
、insert() 、update()、delete() 方法。
(2)、ContentProvider類中的6個抽象方法:
1、boolean onCreate()
2、Uri insert(Uri uri, ContentValues values)
3、int delete(Uri uri, String selection, String[] selectionArgs)
4、int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
5、Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder)
6、String getType(Uri uri)
(3)、ContentProvider類中6個抽象方法的說明:
1、onCreate() 初始化provider
2、query() 返回數據給調用者
3、insert() 插入新數據到ContentProvider
4、update() 更新ContentProvider已存在的數據
5、delete() 從ContentProvider中刪除數據
6、getType() 返回ContentProvider數據的Mime類型
(4)、在清單文件中聲明注冊ContentProvider:
<provider android:name=".MyWordsProvider"
android:authorities="com.steven.wordscontentprovider"
android:exported="true" />
//android:name 屬性的值是:ContentProvider類的子類的完全路徑;
//android:authorities 屬性的值是:content:URI中authority部份。1般就是將name屬性的值全小寫。
//android:exported 屬性是不是允許其他利用調用。如果是false,則該ContentProvider不允許其他利用調用。
(5)、UriMatcher:
繼承ContentProvider類后發現,ContentProvider類中只有1個onCreate()生命周期方法——當其他利用程序通過ContentResolver第1次訪問ContentProvider時,onCreate()會被回調。
其他利用在通過ContentResolver對象履行CRUD操作時,都需要1個重要的參數Uri。為了能順利提供這個Uri參數,Android系統提供了1個UriMatcher工具類。
UriMatcher工具類提供了兩個方法:
1、void addURI(String authority , String path , int code) : 該方法用于向UriMatcher對象注冊Uri。其中authority和path是Uri中的重要部份。而code代表該Uri對應的標示符。
2、int match(Uri uri) : 根據注冊的Uri來判斷指定的Uri對應的標示符。如果找不到匹配的標示符,該方法返回⑴。
private static UriMatcher matcher = null;
static {
// 定義1個Uri匹配器。將UriMatcher.NO_MATCH,即⑴作為參數。
matcher = new UriMatcher(UriMatcher.NO_MATCH);
// 定義1組匹配規則
matcher.addURI(AUTHORITY, "words", 1);
matcher.addURI(AUTHORITY, "newwords", 2);
}
備注:
ContentProvider是單例模式的,當多個利用程序通過使用ContentResolver 來操作使用ContentProvider 提供的數據時,ContentResolver
調用的數據操作會拜托給同1個ContentProvider 來處理。這樣就可以保證數據的1致性。
(6)下面通過1個實例來說解自定義ContentProvider,需要創建兩個工程,1個工程用來自定義ContentProvider,然后把uri在程序清單中暴漏出去,那末此工程就相當于1個服務器端,可以供其他的工程來訪問其數據;另外1個工程相當于客戶端,通過使用ContentResolver
來操作使用ContentProvider 提供的數據。在測試時要先啟動服務端,再啟動客服端。
1,自定義ContentProvider的工程:
①創建1個繼承ContentProvider類:
package com.qf.mycontentprovide;
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.support.annotation.Nullable;
/**
* 多個利用共用同1個
數據庫,
數據庫就是1個db文件
*
數據庫支持直接操作db文件,為何還要用內容提供者?
* 答:出于安全的斟酌,內容提供者可以根據的自己的意愿選擇性的提供數據給客戶端使用。
*
*
服務器和客戶端,安卓有jdbc的api,意味著安卓是可以直接訪問
數據庫的,
* 但是實際中我們使用接口訪問遠程
服務器,這個接口提供給數據給我們的同時也是對遠程
數據庫提供了保護,
* 可以選擇性的返回數據給客戶端
*/
public class MyContentProvider extends ContentProvider{
private SQLiteDatabase database;
private UriMatcher uriMatcher;
/**
* 安裝以后會履行,以后app啟動不會履行
* 并且利用沒有啟動的時候,其他利用也是可以訪問自己提供的數據的
* 和
數據庫的openhelper中的oncreate不1樣,
數據庫是卸載再安裝才會履行,
* 而MyContentProvider只要重新安裝就會履行
*/
@Override
public boolean onCreate() {
DbHelper dbHelper = new DbHelper(getContext());
database = dbHelper.getReadableDatabase();
//獲得到1個uri匹配對象
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/**
* addURI是把authority和path進行拼接
* code是給path設置了1個id
*/
uriMatcher.addURI("com.qf.mycontentprovide.MyContentProvider","person",1);
uriMatcher.addURI("com.qf.mycontentprovide.MyContentProvider","teacher",2);
return true;
}
/**
* 操作
數據庫時,由于
數據庫有多張表,需要判斷操作那張表,
* 這時候addURI的參數code就有了用武之地
*/
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor cursor = null;
int match = uriMatcher.match(uri);
switch (match){
//person表
case 1:
cursor = database.query("person", projection, selection, selectionArgs, null, null, sortOrder);
break;
//teacher表
case 2:
cursor = database.query("teacher", projection, selection, selectionArgs, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
/**
* ContentValues里封裝了1個HashMap<String, Object> mValues;
* 和普通的map的區分:鍵只能為string
* @param uri 客戶端傳過來的uri路徑
* @param values 客戶端封裝的數據傳過來
* @return
*/
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
int match = uriMatcher.match(uri);
long num = 0; //插入數據受影響的行數
switch (match){
case 1:
num = database.insert("person", null, values);
break;
case 2:
num = database.insert("teacher",null,values);
break;
default:
break;
}
//把受影響的行數拼接到uri后面
Uri uri1 = ContentUris.withAppendedId(uri, num);
return uri1;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int match = uriMatcher.match(uri);
int num = 0;
switch (match){
case 1:
num = database.delete("person", selection, selectionArgs);
break;
case 2:
num = database.delete("person", selection, selectionArgs);
break;
}
return num;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int match = uriMatcher.match(uri);
int num = 0;
switch (match){
case 1:
num = database.update("person", values, selection, selectionArgs);
break;
case 2:
num = database.update("teacher",values,selection,selectionArgs);
break;
}
return num;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
}
②創建1個
數據庫操作類,用來向外提供數據:
package com.qf.mycontentprovide;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by Administrator on 2016/9/20.
* 支持內容提供者向外提供數據的
數據庫
*/
public class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, "Person.db", null, 2);
}
/**
* 創建
數據庫時創建1張person表,并給表初始化1條數據
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table person(_id integer primary key autoincrement,name text,pass text)");
db.execSQL("insert into person(name,pass)values('張飛','123')");
}
/**
* 更新
數據庫時,再創建1張teacher表,并初始化1條數據
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("create table teacher(_id integer primary key autoincrement,name text,pass text)");
db.execSQL("insert into person(name,pass)values('老張','12334')");
}
}
③在清單文件中暴漏此內容提供者:
<span style="color:#464646;"><?xml version="1.0" encoding="utf⑻"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qf.mycontentprovide">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- authorities:向外提供數據的接口,即uri,1般為包名+類名
exported:是不是支持其他利用訪問自己的數據,設置為true -->
</span><span style="color:#ff0000;"><provider
android:authorities="com.qf.mycontentprovide.MyContentProvider"
android:name=".MyContentProvider"
android:exported="true">
</provider></span><span style="color:#464646;">
</application>
</manifest></span>
由于MainActivity和activity_main.xml中不需要寫代碼,所以就不再給出。
2.再創建1個去同享內容提供者中的數據的工程:
①布局文件activity_main.xml中的代碼:
<?xml version="1.0" encoding="utf⑻"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.client.MainActivity">
<Button
android:id="@+id/query_person"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="查詢person表" />
<Button
android:id="@+id/query_teacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="查詢teacher表" />
<Button
android:id="@+id/insert_person"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="插入數據到person表" />
<Button
android:id="@+id/insert_teacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="插入數據到teacher表" />
<Button
android:id="@+id/delete_person"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除person表中的數據" />
<Button
android:id="@+id/delete_teacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除teacher表中的數據" />
<Button
android:id="@+id/updata_person"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改person表中的數據" />
<Button
android:id="@+id/updata_teacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改teacher表中的數據" />
</LinearLayout>
②MainActivity中的代碼:
package com.example.client;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ContentResolver contentResolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件,并給控件設置監聽
findViewById(R.id.query_person).setOnClickListener(this);
findViewById(R.id.query_teacher).setOnClickListener(this);
findViewById(R.id.insert_person).setOnClickListener(this);
findViewById(R.id.insert_teacher).setOnClickListener(this);
findViewById(R.id.delete_person).setOnClickListener(this);
findViewById(R.id.delete_teacher).setOnClickListener(this);
findViewById(R.id.updata_person).setOnClickListener(this);
findViewById(R.id.updata_teacher).setOnClickListener(this);
//取得ContentResolver對象來操作
數據庫
contentResolver = getContentResolver();
}
@Override
public void onClick(View v) {
//person表的uri
Uri personUri = Uri.parse("content://com.qf.mycontentprovide.MyContentProvider/person");
//teacher表的uri
Uri teacherUri = Uri.parse("content://com.qf.mycontentprovide.MyContentProvider/teacher");
switch (v.getId()){
//查詢person表
case R.id.query_person:
Cursor cursor = contentResolver.query(personUri, new String[]{"name", "pass"}, null, null, null,null);
while(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex("name"));
String pass = cursor.getString(cursor.getColumnIndex("pass"));
Log.e("name",name);
Log.e("pass",pass);
}
break;
//查詢teacher表
case R.id.query_teacher:
Cursor cursor2 = contentResolver.query(teacherUri, new String[]{"name", "pass"}, null, null, null,null);
while(cursor2.moveToNext()){
String name = cursor2.getString(cursor2.getColumnIndex("name"));
String pass = cursor2.getString(cursor2.getColumnIndex("pass"));
Log.e("name",name);
Log.e("pass",pass);
}
break;
case R.id.insert_person:
ContentValues values = new ContentValues();
values.put("name","關羽");
values.put("pass","456");
Uri insert = contentResolver.insert(personUri, values);
long num = ContentUris.parseId(insert);
Log.e("num",num + "");
break;
case R.id.insert_teacher:
ContentValues values2 = new ContentValues();
values2.put("name","曹操");
values2.put("pass","321");
Uri insert2 = contentResolver.insert(teacherUri, values2);
long num2 = ContentUris.parseId(insert2);
Log.e("num",num2 + "");
break;
case R.id.delete_person:
int num3 = contentResolver.delete(personUri, "name = ?", new String[]{"張飛"});
Log.e("num3",num3 + "");
break;
case R.id.delete_teacher:
int num4 = contentResolver.delete(teacherUri, "name = ?", new String[]{"老張"});
Log.e("num4",num4 + "");
break;
case R.id.updata_person:
ContentValues values3 = new ContentValues();
values3.put("name","關羽");
values3.put("pass","789");
int num5 = contentResolver.update(personUri, values3, null, null);
Log.e("num5",num5 + "");
break;
case R.id.updata_teacher:
ContentValues values4 = new ContentValues();
values4.put("name","曹操");
values4.put("pass","246");
int num6 = contentResolver.update(personUri, values4, null, null);
Log.e("num6",num6 + "");
break;
}
}
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈