Android笔记(五十六) Android四大组件之一——ContentProvider,实现自己的ContentProvider MyContentProvider MyContentResolver

      有时候我们自己的程序也需要向外接提供数据,那么就需要我们自己实现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.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:andro>
    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操作了。