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

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

// DatabaseTest-DatabaseProvider.java
public 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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值