程序员人生 网站导航

自定义ContentProvider

栏目:综合技术时间:2016-11-19 14:52:14

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









------分隔线----------------------------
------分隔线----------------------------

最新技术推荐