«

Android核心基础-5.Android 数据存储与访问-4. ContentProvider 内容提供者

时间:2024-3-2 17:02     作者:韩俊     分类: Android


续上一博文(Android核心基础-5.Android 数据存储与访问-3. 使用Sqlite进行数据存储)

四、 ContentProvider 内容提供者

4.1 什么是ContentProvider

ContentProvider是安卓四大组件之一, 用来共享应用程序内的数据
该组件对外提供了其他应用可以直接访问的增删改查方法
在数据被修改的时候, 可以使用ContentObserver监听

4.2 创建ContentProvider***

定义类继承ContentProvider
在清单文件中声明< provider>标签

4.3 访问ContentProvider***

获取ContentResolver对象
使用ContentResolver指定Uri即可对指定的ContentProvider增删改查

4.4 增删改查方法*

ContentProvider的insert(), delete(), update(), query(): 对外提供的4个操作数据的方法
ContentResolver的insert(), delete(), update(), query(): 调用ContentProvider的方法
SQLiteDabase的insert(), delete(), update(), query(): 在ContentProvider中适合用这4个方法操作数据库, 其内部就是拼接SQL语句, 调用execSQL()和rawQuery()

4.5 UriMatcher*

UriMatcher可以用来匹配Uri, 识别出子级路径
addUri()方法可以指定路径和结果码
match()方法可以匹配一个Uri, 得到结果码

4.6 带id的Uri*

可以使用UriMatcher添加一个带”#”的路径, 用来匹配带id的Uri
使用ContentUris.parseId()可以从Uri中解析出id

4.7 ContentObserver监听数据修改**

可以使用ContentResolver, 调用registerContentObserver()注册一个ContentObserver
在数据修改时使用ContentResolver调用notifyChange()发一个通知
ContentObserver会收到这个通知, 执行内部的onChange()方法

发送通知:

// 当数据改变时, 发送通知, 这时ContentObserver就会接收到
getContext().getContentResolver().notifyChange(uri, null); 

监听通知:

// 注册一个ContentObserver(类似一个监听器), 其中需要实现onChange()方法, 在数据修改的时候, 会自动执行onChange()方法
Uri uri = Uri.parse("content://net.dxs.provider");
//参数二:是否接收后代通知,如content://net.dxs.provider/account
getContentResolver().registerContentObserver(uri, true, new MyObserver());

private class MyObserver extends ContentObserver {
    public MyObserver() {
        super(new Handler());
    }

    @Override
    public void onChange(boolean selfChange) {
        list = dao.queryPage(20, pageNum); // 重新查询数据
        adapter.notifyDataSetChanged(); // 刷新ListView(把数据和ListView显示的内容同步)
    }
}

4.8 监听短信

从github上下载telephonyprovider, 从清单文件中获取Uri
在程序中对指定Uri注册ContentObserver, 当收发短信时就会执行onChange()
查询到最后一条数据就是短信记录

4.9 ContentProvider匹配说明


1. schema,用来说明一个ContentProvider控制这些数据。 “content://”
2. 主机名或授权(Authority),它定义了是哪个ContentProvider提供这些数据。
3. path路径,URI下的某一个Item。
4. ID, 通常定义Uri时使用”#”号占位符代替, 使用时替换成对应的数字
“content://net.dxs.provider/person/#” #表示数据id(#代表任意数字)”content://net.dxs.provider/person/* ” *来匹配任意文本

要给第三方提供数据访问的ContentProvider类
DxsProvider.java

package net.dxs.sqlite.provider;

import net.dxs.sqlite.dao.MyHelper;
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;

public class DxsProvider extends ContentProvider {
    private MyHelper helper;
    private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); // 创建匹配器对象, 当Uri无法匹配的时候, 得到-1
    private static final int ACCOUNT_ID = 0;
    private static final int ACCOUNT = 1;
    private static final int ORDER = 2;

    @Override
    public boolean onCreate() { // 创建之后执行
        System.out.println("DxsProvider--->onCreate");
        helper = new MyHelper(getContext());
        matcher.addURI("net.dxs.provider", "account/#", ACCOUNT_ID);
        matcher.addURI("net.dxs.provider", "account", ACCOUNT); // 向匹配器中添加可以识别的Uri, 指定结果码
        matcher.addURI("net.dxs.provider", "order", ORDER);
        return false;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        System.out.println("DxsProvider--->insert");
        switch (matcher.match(uri)) { // 使用匹配器识别Uri, 得到预先指定的结果码
        case ACCOUNT:
            SQLiteDatabase db = helper.getWritableDatabase();
            long id = db.insert("account", "_id", values); // 通过values拼接SQL语句
            getContext().getContentResolver().notifyChange(uri, null);
            db.close();
            return ContentUris.withAppendedId(uri, id); // 把新记录的id拼在Uri最后, 返回
        case ORDER:
            System.out.println("暂时没有order表");
            return null;
        default:
            throw new IllegalArgumentException("Uri无法识别: " + uri);
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        System.out.println("DxsProvider--->delete");
        switch (matcher.match(uri)) {
        case ACCOUNT_ID:
            long id = ContentUris.parseId(uri);
            selection = "_id=?";
            selectionArgs = new String[] { id + "" };
        case ACCOUNT:
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.delete("account", selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null);
            db.close();
            return count;
        default:
            throw new IllegalArgumentException("Uri无法识别: " + uri);
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        System.out.println("DxsProvider--->update");
        switch (matcher.match(uri)) {
        case ACCOUNT_ID:
            long id = ContentUris.parseId(uri);
            selection = "_id=?";
            selectionArgs = new String[] { id + "" };
        case ACCOUNT:
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.update("account", values, selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null); // 当数据改变时, 发送通知, 这时ContentObserver就会接收到
            db.close();
            return count;
        default:
            throw new IllegalArgumentException("Uri无法识别: " + uri);
        }
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        System.out.println("DxsProvider--->query");
        switch (matcher.match(uri)) {
        case ACCOUNT_ID:
            long id = ContentUris.parseId(uri); // 截取最后一个"/"后面的数字, 转为long
            selection = "_id=?";
            selectionArgs = new String[] { id + "" };
        case ACCOUNT:
            SQLiteDatabase db = helper.getReadableDatabase();
            Cursor c = db.query("account", projection, selection, selectionArgs, null, null, sortOrder);
            return c;
        default:
            throw new IllegalArgumentException("Uri无法识别: " + uri);
        }
    }

    @Override
    public String getType(Uri uri) { // 获取Uri的MimeType, text/html  text/css   image/jpg   audio/mp3
        System.out.println("DxsProvider--->getType");
        switch (matcher.match(uri)) {
        case ACCOUNT_ID:
            return "vnd.android.cursor.item/account";
        case ACCOUNT:
            return "vnd.android.cursor.dir/account";
        default:
            throw new IllegalArgumentException("Uri无法识别: " + uri);
        }
    }
}

注意清单文件要注册声明provider

<provider
    android:name="net.dxs.sqlite.provider.DxsProvider"
    android:authorities="net.dxs.provider"
    android:exported="true" />

第三方APP开始调用提供的ContentProvider

package net.dxs.other;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;

public class ProviderTest extends AndroidTestCase {

    public void test1() {
        ContentResolver resolver = getContext().getContentResolver(); // 获取ContentResolver
        Uri uri = Uri.parse("content://net.dxs.provider"); // 指定ContentProvider的Uri
        // resolver.delete(uri, null, null); // 对指定Uri调用删除方法
        resolver.query(uri, null, null, null, null);
    }

    public void testInsert() {
        ContentResolver resolver = getContext().getContentResolver();
        Uri uri = Uri.parse("content://net.dxs.provider/account");
        ContentValues values = new ContentValues();
        values.put("name", "insert");
        values.put("balance", 23456);
        System.out.println(resolver.insert(uri, values)); // 得到刚刚插入的Uri
    }

    public void testDelete() {
        ContentResolver resolver = getContext().getContentResolver();
        Uri uri = Uri.parse("content://net.dxs.provider/account/20");
        resolver.delete(uri, null, null);
    }

    public void testUpdate() {
        ContentResolver resolver = getContext().getContentResolver();
        Uri uri = Uri.parse("content://net.dxs.provider/account/1");
        ContentValues values = new ContentValues();
        values.put("name", "深情小建");
        values.put("balance", 20000);
        resolver.update(uri, values, null, null);
    }

    public void testQuery() {
        ContentResolver resolver = getContext().getContentResolver();
        Uri uri = Uri.parse("content://net.dxs.provider/account/100");
        Cursor c = resolver.query(uri, null, null, null, null);
        while (c.moveToNext()) {
            System.out.println(c.getString(c.getColumnIndex("name")) + ": " + c.getInt(c.getColumnIndex("balance")));
        }
        c.close();
    }

    public void testGetType() {
        ContentResolver resolver = getContext().getContentResolver();
        System.out.println(resolver.getType(Uri.parse("content://net.dxs.provider/account/100"))); // 单条记录, 返回item
        System.out.println(resolver.getType(Uri.parse("content://net.dxs.provider/account"))); // 多条记录, 返回dir
    }
}

生成的数据库表如图

实例源代码->百度网盘

标签: android

热门推荐