有时候我们自己的程序也需要向外接提供数据,那么就需要我们自己实现ContentProvider。
自己实现ContentProvider的话需要新建一个类去继承ContentProvider,然后重写类中的的6个抽象方法。
onCreate():初始化内容提供器时候会调用,通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败,注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供其才会被初始化
query():从内容提供其中查询数据,使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询结果存放在Cursor对象中返回。
insert():向内容提供器中添加一条数据,使用uri参数来确定要添加到的表,待添加的数据保存在values参数中,添加完成后,返回一个用于表示这条新记录的URI。
update():更新内容提供器中已有的数据,使用uri参数来确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约束更新哪些列,受影响的行数将作为返回值返回。
delete():从内容提供其中删除数据,使用uri参数来确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。
getType():根据传入的内容URI来返回相应的MIME类型。
可以看到,几乎每一个方法都会带有Uri这个参数,这个参数也正是调用ContentResolver的增删改查方法时传递过来的,而现在,我们需要对传入的Uri参数进行解析,从中分析出调用方期待访问的表和数据。
一般的标准的内容URI写法是这样的
content://com.example.app.provider/table1
这就表示调用方期待访问的是com.example.app这个应用的table1表中的数据。除此之外,我们还可以在这个内容URI的后面加上一个id,例如
content://com.example.app.provider/table1/1
这就表示调用方期待访问的是com.example.app这个应用的table1表中的id为1的数据。
内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以id结尾就表示期望访问该表中拥有相应的id的数据,我们可以使用通配符的方式来分别匹配这两种格式的内容URI,规则如下
1.*表示匹配任意长度的任意字符
2.#表示匹配任意长度的数据
所以一个能够匹配任意表的内容URI格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配table1表中任意一行数据的内容URI格式就可以写成
content://com.example.app.provider/table1/#
接着我们再借助UriMatcher这个类就可以轻松的实现匹配内容URI的功能,UriMatcher中提供了一个addURI()方法,这个方法接收三个参数,可以分别把权限,路径和一个自定义代码传递进去,这样,当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期待访问的是哪张表中的数据了。
除此之外,还有一个getTypt()方法,它是所有的内容提供其都必须提供的一个方法,用于获取Uri对象所对应的MIME类型,一个内容URI所对应的MIME字符串主要由三部分组成,Android对这三个部分做了如下格式规定:
1.必须以vnd开头
2.如果内容URI以路径结尾,则后面接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/。
3.最后接上vnd.<authority>.<path>
简单示例:
MyContentProvider
MyContentProvider.java
package cn.lixyz.mycontentprovider; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; public class MyContentProvider extends ContentProvider { public static final int STUDENTS_DIR = 0; public static final int STUDENTS_ITEM = 1; public static final int CLASSES_DIR = 2; public static final int CLASSES_ITEM = 3; private static UriMatcher uriMatcher; private MyDBHelper myDBHelper; private SQLiteDatabase database; private static final String AUTHORITY = "cn.lixyz.mycontentprovider.cp"; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students", STUDENTS_DIR); uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "students/#", STUDENTS_ITEM); uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes", CLASSES_DIR); uriMatcher.addURI("cn.lixyz.mycontentprovider.cp", "classes/#", CLASSES_ITEM); } @Override public boolean onCreate() { myDBHelper = new MyDBHelper(getContext(), "school.db", null, 1); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { database = myDBHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case STUDENTS_DIR: cursor = database.query("students", projection, selection, selectionArgs, null, null, sortOrder); break; case STUDENTS_ITEM: String studentID = uri.getPathSegments().get(1); cursor = database.query("students", projection, "_id=?", new String[] { studentID }, null, null, sortOrder); break; case CLASSES_DIR: cursor = database.query("classes", projection, selection, selectionArgs, null, null, sortOrder); break; case CLASSES_ITEM: String classID = uri.getPathSegments().get(1); cursor = database.query("classes", projection, "_id=?", new String[] { classID }, null, null, sortOrder); break; } return cursor; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case STUDENTS_DIR: return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.students"; case STUDENTS_ITEM: return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.students"; case CLASSES_DIR: return "vnd.android.cursor.dir/vnd.cn.lixyz.mycontentprovider.cp.classes"; case CLASSES_ITEM: return "vnd.android.cursor.item/vnd.cn.lixyz.mycontentprovider.cp.classes"; } return null; } @Override public Uri insert(Uri uri, ContentValues values) { database = myDBHelper.getWritableDatabase(); Uri returnUri = null; switch (uriMatcher.match(uri)) { case STUDENTS_DIR: case STUDENTS_ITEM: long newStudent = database.insert("students", null, values); returnUri = Uri.parse("content://" + AUTHORITY + "/students/" + newStudent); break; case CLASSES_DIR: case CLASSES_ITEM: long newClass = database.insert("classes", null, values); returnUri = Uri.parse("content://" + AUTHORITY + "/classes/" + newClass); break; } return returnUri; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } class MyDBHelper extends SQLiteOpenHelper { private Context mContext; public MyDBHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); this.mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL( "create table if not exists students (_id integer primary key autoincrement,studentName text,studentAge integer,class text)"); db.execSQL("create table if not exists classes (_id integer primary key autoincrement,className text)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } } }
AndroidManifest.xml
<provider android:name="MyContentProvider" android:authorities="cn.lixyz.mycontentprovider.cp" android:exported="true" > </provider>
MyContentResolver
MainActivity.java
package cn.lixyz.mycontentresolver; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } public void clickButton(View view) { switch (view.getId()) { case R.id.bt_addclass: addClass(); break; case R.id.bt_addstudent: addStudent(); break; case R.id.searchclass: searchClass(); break; case R.id.searchstudent: searchStrudent(); break; } } // 搜索学生方法 private void searchStrudent() { Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students"); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); while (cursor.moveToNext()) { String tudentName = cursor.getString(cursor.getColumnIndex("studentName")); int studentAge = cursor.getInt(cursor.getColumnIndex("studentAge")); String className = cursor.getString(cursor.getColumnIndex("class")); Log.d("TTTT", "学生姓名:" + tudentName + ",年龄 : " + studentAge + ",所在班级:" + className); } } } // 搜索班级方法 private void searchClass() { Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes"); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); while (cursor.moveToNext()) { String className = cursor.getString(cursor.getColumnIndex("className")); Log.d("TTTT", "班级:" + className); } } } // 添加学生方法 private void addStudent() { String studentName = et_studentname.getText().toString().trim(); String studentAge = et_studentage.getText().toString().trim(); String studentClass = et_studentclass.getText().toString().trim(); Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/students"); ContentResolver contentResolver = getContentResolver(); ContentValues cv = new ContentValues(); cv.put("studentName", studentName); cv.put("studentAge", studentAge); cv.put("class", studentClass); Uri returnUri = contentResolver.insert(uri, cv); Log.d("TTTT", "returnUri:" + returnUri.toString()); } // 添加班级方法 private void addClass() { ContentResolver contentResolver = getContentResolver(); Uri uri = Uri.parse("content://cn.lixyz.mycontentprovider.cp/classes"); String className = et_addclass.getText().toString().trim(); ContentValues cv = new ContentValues(); cv.put("className", className); contentResolver.insert(uri, cv); } private EditText et_addclass, et_studentname, et_studentage, et_studentclass; private Button bt_addclass, bt_addstudent, searchclass, searchstudent; private void initView() { et_addclass = (EditText) findViewById(R.id.et_addclass); et_studentname = (EditText) findViewById(R.id.et_studentname); et_studentage = (EditText) findViewById(R.id.et_studentage); et_studentclass = (EditText) findViewById(R.id.et_studentclass); bt_addclass = (Button) findViewById(R.id.bt_addclass); bt_addstudent = (Button) findViewById(R.id.bt_addstudent); searchclass = (Button) findViewById(R.id.searchclass); searchstudent = (Button) findViewById(R.id.searchstudent); } }
activity_main.xml
<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:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="cn.lixyz.mycontentresolver.MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加班级" /> <EditText android:id="@+id/et_addclass" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入班级名称" /> <Button android:id="@+id/bt_addclass" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="clickButton" android:text="添 加" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加学生" /> <EditText android:id="@+id/et_studentname" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入学生姓名" /> <EditText android:id="@+id/et_studentage" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入学生年龄" /> <EditText android:id="@+id/et_studentclass" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入学生班级" /> <Button android:id="@+id/bt_addstudent" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="clickButton" android:text="添 加" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="搜索" /> <Button android:id="@+id/searchclass" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="clickButton" android:text="点我搜索班级" /> <Button android:id="@+id/searchstudent" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="clickButton" android:text="点我搜索学生" /> </LinearLayout>
这样,就可以在ContentResolver应用中,对ContentProvider应用的数据库进行insert和query操作了。