复习Android之ContentProvider详解

本文深入解析了Android中的ContentProvider,从数据库类的创建到自定义ContentProvider的实现,再到通过ContentResolver进行数据操作的全过程。同时介绍了ContentProvider的安全性和高效访问特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ContentProvider的底层是采用 Android中的Binder机制。
ContentProvider是一个抽象类,并且实现ComponentCallbacks2接口

abstract class ContentProvider implements ComponentCallbacks2

我们开发自己的内容提供者我们就需要继承ContentProvider这个类并复写其方法,此类用来共享该应用的数据:

在这里插入图片描述
步骤1:创建数据库类

public class DBHelper extends SQLiteOpenHelper {

    // 数据库名
    private static final String DATABASE_NAME = "content_helper.db";

    // 用户表名
    public static final String USER_TABLE_NAME = "user";

    private static final int DATABASE_VERSION = 1;
    //数据库版本号

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        // 创建用户表
        db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)   {

    }
}

步骤2:自定义UserContentProvider的代码如下

public class UserContentProvider extends ContentProvider {
    // 设置ContentProvider的唯一标识
    public static final String AUTOHORITY = "com.click.UserProvider";
    public static final int User_Code = 1;

    private Context mContext;
    public DBHelper mDbHelper = null;
    public SQLiteDatabase db = null;

    // UriMatcher类使用:在ContentProvider 中注册URI
    private static final UriMatcher mMatcher;

    static {
        // 初始化
        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mMatcher.addURI(AUTOHORITY, "user", User_Code);

    }
    //在创建ContentProvider时使用
    @Override
    public boolean onCreate() {
        mContext = getContext();
        // 在ContentProvider创建时对数据库进行初始化
        // 运行在主线程,故不能做耗时操作,此处仅作展示
        mDbHelper = new DBHelper(getContext());
        db = mDbHelper.getWritableDatabase();

        // 初始化(先清空表,再加入数据)
        db.execSQL("delete from user");
        db.execSQL("insert into user values(1,'张三');");
        db.execSQL("insert into user values(2,'李四');");

        return true;
    }


    /**
     * 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
     */
    private String getTableName(Uri uri) {
        String tableName = null;
        switch (mMatcher.match(uri)) {
            case User_Code:
                tableName = DBHelper.USER_TABLE_NAME;
                break;

        }
        return tableName;
    }

    //用于查询指定uri的数据返回一个Cursor
    @androidx.annotation.Nullable
    @Override
    public Cursor query(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable String[] projection, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs, @androidx.annotation.Nullable String sortOrder) {
        // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
        String table = getTableName(uri);
        // 查询数据
        return db.query(table, projection, selection, selectionArgs, null, null, sortOrder, null);
    }
     //用于返回指定的Uri中的数据MIME类型
    @androidx.annotation.Nullable
    @Override
    public String getType(@androidx.annotation.NonNull Uri uri) {
        return null;
    }
     //用于向指定uri的ContentProvider中添加数据
    @androidx.annotation.Nullable
    @Override
    public Uri insert(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable ContentValues values) {
        String table = getTableName(uri);
        // 添加数据
        db.insert(table, null, values);
        // 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
        mContext.getContentResolver().notifyChange(uri, null);


        return uri;
    }
    //用于删除指定uri的数据
    @Override
    public int delete(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs) {
        return 0;
    }
   //用户更新指定uri的数据
    @Override
    public int update(@androidx.annotation.NonNull Uri uri, @androidx.annotation.Nullable ContentValues values, @androidx.annotation.Nullable String selection, @androidx.annotation.Nullable String[] selectionArgs) {
        return 0;
    }
}

步骤3:向表里边添加数据

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        insert();
    }

    private void insert() {
        /**
         * 对user表进行操作
         */

        // 设置URI
        Uri uri_user = Uri.parse("content://" + UserContentProvider.AUTOHORITY + "/user");
        // 插入表中数据
        ContentValues values = new ContentValues();
        values.put("_id", 3);
        values.put("name", "王五");
        // 获取ContentResolver
        ContentResolver resolver = getContentResolver();
        // 通过ContentResolver 根据URI 向ContentProvider中插入数据
        resolver.insert(uri_user, values);

        // 通过ContentResolver 向ContentProvider中查询数据
        Cursor cursor = resolver.query(uri_user, new String[]{"_id", "name"}, null, null, null);
        while (cursor.moveToNext()) {
            System.out.println("用户信息:" + cursor.getInt(0) + " " + cursor.getString(1));
            // 将表中数据全部输出
        }
        cursor.close();
        // 关闭游标
    }
}

ContentProvider是安卓四大组件之一,所以它和Activity一样也需要我们再xml文件中声明,声明如下:

  <provider
        //authorities唯一标识该内容提供者
        android:authorities="com.click.UserProvider"
         //name名字
        android:name=".UserContentProvider"
        //exported是否允许别的应用访问
        android:exported="true"/>

在这里插入图片描述

其它应用可以通过ContentResolver来访问ContentProvider提供的数据。
URI(Universal Resource Identifier)统一资源定位符,下边我们就详细介绍对应URI代表的意思。

URI:[scheme:][//host:port][path][?query]
例如:
URI:http://www.go007.com:8080/index.html?id=111111

scheme:根据格式我们很容易看出来scheme为http
host:www.go007.com
port:就是主机名后面path前面的部分为8080
path:在port后面?的前面为index.html
query:?之后的都是query部分为 id=111111
在此我们通过其他的应用操作ContentProvider中的数据

public class MainActivity extends AppCompatActivity {
    String uriString = "content://com.click.UserProvider/user";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        insert();
    }

    private void insert() {
        /**
         * 对user表进行操作
         */

        // 设置URI
        Uri uri_user = Uri.parse(uriString);
        // 插入表中数据
        ContentValues values = new ContentValues();
        values.put("_id", 4);
        values.put("name", "马六");
        // 获取ContentResolver
        ContentResolver resolver = getContentResolver();
        // 通过ContentResolver 根据URI 向ContentProvider中插入数据
        resolver.insert(uri_user, values);

        // 通过ContentResolver 向ContentProvider中查询数据
        Cursor cursor = resolver.query(uri_user, new String[]{"_id", "name"}, null, null, null);
        while (cursor.moveToNext()) {
            System.out.println("用户信息:" + cursor.getInt(0) + " " + cursor.getString(1));
            // 将表中数据全部输出
        }
        cursor.close();
        // 关闭游标
    }
}

步骤1:声明可访问的权限

AndroidManifest.xml
//声明本应用可允许通信的权限(读权限)
//<uses-permission android:name="com.aidl.Read"/>
//声明本应用可允许通信的权限(写权限)
//<uses-permission android:name="com.aidl.Write"/>
//声明本应用可允许通信的权限(全权限)
<uses-permission android:name="com.aidl.PROVIDER"/>

在这里插入图片描述
到此ContentProvider就介绍完成了。
优点:

  1. 安全
  2. 访问简单 & 高效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值