当多个利用程序同享同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;
}
}
}