第一行代码-7.3 创建自己的内容提供器

来源:互联网 发布:工业机器人软件平台 编辑:程序博客网 时间:2024/05/17 01:51

  之前我们为了实现SQLite的功能,需要创建自己的DatabaseHelper类,现在我们也可以定义自己的ContentProvider来实现跨应用访问数据。但是六个方法都要重写。
  由于整个MyProvider的实现比较复杂,所以先看代码再解释。在DatabaseTest中创建DatabaseProvider类,注意要把Toast去除掉,因为跨程序访问的时候不能使用Toast。

// DatabaseTest-DatabaseProvider.javapublic class DatabaseProvider extends ContentProvider{    public static final int STUDENT_DIR = 0;    public static final int STUDENT_ITEM = 1;    public static final int SUBJECT_DIR = 2;    public static final int SUBJECT_ITEM = 3;    public static final String AUTHORITY = "com.example.databasetest.provider";    private static UriMatcher uriMatcher;    private MyDatabaseHelper dbHelper;    static {        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);        uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);        uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);        uriMatcher.addURI(AUTHORITY, "subject", SUBJECT_DIR);        uriMatcher.addURI(AUTHORITY, "subject/#", SUBJECT_ITEM);    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        int deletedRows = 0;        switch (uriMatcher.match(uri)) {        case STUDENT_DIR:            deletedRows = db.delete("student", selection, selectionArgs);            break;        case STUDENT_ITEM:            String studentId = uri.getPathSegments().get(1);            deletedRows = db.delete("student", "id = ?", new String[] {studentId});            break;        case SUBJECT_DIR:            deletedRows = db.delete("subject", selection, selectionArgs);            break;        case SUBJECT_ITEM:            String subjectId = uri.getPathSegments().get(1);            deletedRows = db.delete("subject", "id = ?", new String[] {subjectId});            break;        default:            break;        }        return deletedRows;    }    @Override    public String getType(Uri uri) {        switch (uriMatcher.match(uri)) {        case STUDENT_DIR:            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.student";        case STUDENT_ITEM:            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.student";        case SUBJECT_DIR:            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.subject";        case SUBJECT_ITEM:            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.subject";        default:            break;        }        return null;    }    @Override    public Uri insert(Uri uri, ContentValues values) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        Uri uriReturn = null;        switch (uriMatcher.match(uri)) {        case STUDENT_ITEM:            long newStudentId = db.insert("student", null, values);            uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newStudentId);            break;        case SUBJECT_ITEM:            long newSubjectId = db.insert("subject", null, values);            uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newSubjectId);            break;        default:            break;        }        return uriReturn;    }    @Override    public boolean onCreate() {        dbHelper = new MyDatabaseHelper(getContext(), "student.db", null, 1);        return true;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        SQLiteDatabase db = dbHelper.getReadableDatabase();        Cursor cursor = null;        switch (uriMatcher.match(uri)) {        case STUDENT_DIR:            cursor = db.query("student", projection, selection, selectionArgs, null, null, sortOrder);            break;        case STUDENT_ITEM:            String studentId = uri.getPathSegments().get(1);            cursor = db.query("student", projection, "id = ?", new String[] {studentId}, null, null, sortOrder);            break;        case SUBJECT_DIR:            cursor = db.query("subject", projection, selection, selectionArgs, null, null, sortOrder);            break;        case SUBJECT_ITEM:            String subjectId = uri.getPathSegments().get(1);            cursor = db.query("subject", projection, "id = ?", new String[] {subjectId}, null, null, sortOrder);            break;            default:break;        }        return cursor;    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        int updatedRows = 0;        switch (uriMatcher.match(uri)) {        case STUDENT_DIR:            updatedRows = db.update("student", values, selection, selectionArgs);            break;        case STUDENT_ITEM:            String studentId = uri.getPathSegments().get(1);            updatedRows = db.update("student", values, "id = ?", new String[] {studentId});            break;        case SUBJECT_DIR:            updatedRows = db.update("subject", values, selection, selectionArgs);            break;        case SUBJECT_ITEM:            String subjectId = uri.getPathSegments().get(1);            updatedRows = db.update("subject", values, "id = ?", new String[] {subjectId});            break;        default:            break;        }        return updatedRows;    }}

  有几点需要注意的地方:首先是uri.getPathSegments方法,它会把uri权限之后的内容以'/'符号进行分割,并把分割后
的结果放入到一个字符串列表中。根据前面提到的uri的格式,这个列表的第0 个位置存放的就是路径,第1 个位置存放的就是id 了。
  然后是getType方法:它是所有的内容提供器都必须提供的一个方法,用于获取Uri 对象所对应的MIME 类型。一个内容URI 所对应的MIME字符串主要由三部分组分,Android 对这三个部分做了如下格式规定:
1. 必须以vnd 开头。
2. 如果内容URI 以路径结尾,则后接android.cursor.dir/,如果内容URI 以id 结尾,
则后接android.cursor.item/。
3. 最后接上vnd.<authority>.<path>。
  写完了provider,还要在manifest中注册才可以使用:

<!-- DatabaseTest manifest --><provider android:name="com.example.databasetest.DatabaseProvider"   android:authorities="com.example.databasetest.databasetest.provider"></provider>

  最后是uriMatcher里面的方法,涉及到通配符:#的意思是任意长度的数字,*表示任意长度的字符。为什么要用到任意数字的匹配?因为Update和Delete方法都可能要传入行数的参数(也就是id的值),所以需要提取这个数字,就需要在uriMatcher中插入这个匹配。
  终于到了最后一步:在其他应用中对DatabaseTest中的数据库操作。创建ProviderTest项目,并修改布局如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent" android:layout_height="match_parent"    android:orientation="vertical">    <Button android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/insert_button"        android:text="插入数据"/>    <Button android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/query_button"        android:text="遍历数据"/>    <Button android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/update_button"        android:text="更新数据"/>    <Button android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/delete_button"        android:text="删除数据"/></LinearLayout>

  然后是MainActivity.java:

public class MainActivity extends Activity implements OnClickListener{    private Button mBInsert;    private Button mBUpdate;    private Button mBDelete;    private Button mBQuery;    private String newId;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mBInsert = (Button) findViewById(R.id.insert_button);        mBUpdate = (Button) findViewById(R.id.update_button);        mBDelete = (Button) findViewById(R.id.delete_button);        mBQuery = (Button) findViewById(R.id.query_button);        mBInsert.setOnClickListener(this);        mBUpdate.setOnClickListener(this);        mBDelete.setOnClickListener(this);        mBQuery.setOnClickListener(this);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }    @Override    public void onClick(View view) {        Uri uri;        ContentValues values;        switch (view.getId()) {        case R.id.insert_button:            // 添加数据            uri = Uri.parse("content://com.example.databasetest.provider/student");            values = new ContentValues();            values.put("no", "23");            values.put("name", "James");            values.put("number", "112233");            Uri newUri = getContentResolver().insert(uri, values);            newId = newUri.getPathSegments().get(1);            break;        case R.id.query_button:            // 遍历数据            uri = Uri.parse("content://com.example.databasetest.provider/student");            Cursor cursor = getContentResolver().query(uri, null, null, null, null);            if (cursor != null) {                while (cursor.moveToNext()) {                    String name = cursor.getString(cursor.getColumnIndex("name"));                    String no = cursor.getString(cursor.getColumnIndex("no"));                    String number = cursor.getString(cursor.getColumnIndex("number"));                    Log.d("sysu", name);                    Log.d("sysu", no);                    Log.d("sysu", number);                }                cursor.close();            }            break;        case R.id.update_button:            // 更新数据            uri = Uri.parse("content://com.example.databasetest.provider/student/"+newId);            values = new ContentValues();            values.put("no", "6");            values.put("name", "James");            values.put("number", "112233");            getContentResolver().update(uri, values, "id = ?", new String[] {newId});            break;        case R.id.delete_button:            // 删除数据            uri = Uri.parse("content://com.example.databasetest.provider/student/"+newId);            getContentResolver().delete(uri, null, null);            break;        default:            break;        }    }}

  实现效果:

这里写图片描述
  总结一下:ContentProvider是建立在数据存储的基础上实现的,只不过在访问另一个应用的数据的时候,需要借助uri访问,uri包括权限和参数(比如id的值),需要注意格式。在数据存储的应用中借助UriMatch判断出要访问的数据是什么。最后要注意getType的格式。

0 0