四大组件之ContentProvider

本文详细介绍了Android中的ContentProvider组件,包括其作用、实现原理及如何在实际项目中使用。通过具体的案例,展示了如何自定义Provider暴露数据库表数据供其他应用访问,并演示了如何使用ContentResolver进行查询、更新、删除等操作。

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

理论概述

为什么要有ContentProvider?

  • 功能需求: 一个应用需要访问另一个应用的数据库表数据
  • 实际情况: 一个应用的数据库文件是应用私有的, 其它应用不能直接访问

ContentProvider是什么?

  • ContentProvider是四大应用组件之一
  • 当前应用使用ContentProvider将数据库表数据操作暴露给其它应用访问
  • 其它应用需要使用ContentResolver来调用ContentProvider的方法
  • 它们之间的调用是通过Uri来进行交流的

相关API

ContentProvider : 内容提供者类

//provider对象创建后调用(应用安装成功或手机启动完成)
public abstract boolean onCreate();

//查询表数据
Cursor query(Uri uri, String[] projection,String selection,
String[] selectionArgs)

//插入表数据
Uri insert(Uri uri, ContentValues values);

//删除表数据
int delete(Uri uri, String selection, String[] selectionArgs)

//更新表数据
update(Uri uri, ContentValues values, String selection,String[] selectionArgs);

ContentResolver: 内容提供者的解析类

//得到它的对象
context.getContentResolver()

//调用provider进行数据库CRUD操作
Insert()、delete()、update()、query()

//注册uri的监听
registerContentObserver(Uri uri, boolean notify,ContentObserver observer)

//解注册uri的监听
unregisterContentObserver(ContentObserver observer)

//通知监听器
notifyChange(Uri uri, ContentObserver observer)

Uri: 包含请求地址数据的类

//得到其对象
Uri static parse(String uriString)
这里写图片描述
UriMatcher : 用于匹配Uri的容器

//添加一个合法的URI
void addURI(String authority, String path, int code)

//匹配指定的uri, 返回匹配码
int match(Uri uri)

ContentUris : 解析uri的工具类

//解析uri, 得到其中的id
long parseId(Uri contentUri)

//添加id到指定的uri中
Uri withAppendedId(Uri contentUri, long id)

案例一:自定义两个应用

定义一个provide项目
首先定义一个数据库操作类
public class DBHelper extends SQLiteOpenHelper {
    public DBHelper(Context context) {
        super(context, "dongge2.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.e("TAG", "onCreate()...");
        //建表
        db.execSQL("create table person(_id integer primary key autoincrement, name varchar)");
        //初始化数据
        db.execSQL("insert into person (name) values ('Tom')");
    }

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

    }
}
自定义一个provider:将自己的数据库表数据暴露给其他应用使用
public class PersonProvider extends ContentProvider {
    private DBHelper dbHelper;
    //用来存放所有合法的Uri的容器
    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    private int deleteCount;

    public PersonProvider() {
        Log.e("TAG", "PersonProvider()");
    }

    //保存一些合法的uri
    //contetn://com.hbwj.serviceclient.personprovider/person不根据id操作
    //contetn://com.hbwj.serviceclient.personprovider/person/1根据id操作
    static {
        matcher.addURI("com.hbwj.serviceclient.personprovider", "/person", 1);
        matcher.addURI("com.hbwj.serviceclient.personprovider", "/person/#", 2);//#匹配任意数字
    }

    @Override
    public boolean onCreate() {
        Log.e("TAG", "PersonProvider onCreate()");
        dbHelper = new DBHelper(getContext());

        return false;
    }

    //contetn://com.hbwj.serviceclient.personprovider/person 不根据id查询
    //contetn://com.hbwj.serviceclient.personprovider/person/1根据id查询
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        Log.e("TAG", "PersonProvider query()");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //匹配url,返回code
        int code = matcher.match(uri);
        if (code == 1) {//不根据id查询
            Cursor cursor = database.query("person", projection, selection, selectionArgs, null, null, null);
            return cursor;
        } else if (code == 2) {//根据id查询
            long id = ContentUris.parseId(uri);
            Cursor cursor = database.query("person", null, "_id=?", new String[]{id + ""}, null, null, null);
            return cursor;
        } else {//如果不合法抛出异常
            throw new RuntimeException("查询的uri不合法");
        }
    }


    //contetn://com.hbwj.serviceclient.personprovider/person 不根据id插入
    //contetn://com.hbwj.serviceclient.personprovider/person/1根据id插入(没有)
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        Log.e("TAG", "PersonProvider insert()");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //匹配url,返回code
        int code = matcher.match(uri);
        //如果合法, 进行插入
        if (code == 1) {
            long id = database.insert("person", null, values);
            //将id添加到uri中
            uri = ContentUris.withAppendedId(uri, id);
            database.close();
            return uri;
        } else {
            //如果不合法抛出异常
            database.close();
            throw new RuntimeException("插入uri不合法");
        }
    }

    //contetn://com.hbwj.serviceclient.personprovider/person 不根据id删除
    //contetn://com.hbwj.serviceclient.personprovider/person/1根据id删除
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.e("TAG", "PersonProvider delete()");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //匹配url,返回code
        int code = matcher.match(uri);
        //如果合法, 进行删除
        int deleteCount = 0;
        if (code == 1) {//不根据id删除
            deleteCount = database.delete("person", selection, selectionArgs);
        } else if (code == 2) {//根据id删除
            long id = ContentUris.parseId(uri);
            deleteCount = database.delete("person", "_id=" + id, null);
        } else {
            //如果不合法, 抛出异常
            database.close();
            throw new RuntimeException("刪除的uri不合法");
        }
        return deleteCount;
    }

    //contetn://com.hbwj.serviceclient.personprovider/person 不根据id更新
    //contetn://com.hbwj.serviceclient.personprovider/person/1根据id更新
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.e("TAG", "PersonProvider update()");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //匹配url,返回code
        int code = matcher.match(uri);
        //如果合法, 进行删除
        int updateCount = 0;
        if (code == 1) {//不根据id更新
            updateCount = database.update("person", values, selection, selectionArgs);
        } else if (code == 2) {//根据id更新
            long id = ContentUris.parseId(uri);
            updateCount = database.update("person", values, "_id=" + id, null);
        } else {
            //如果不合法, 抛出异常
            database.close();
            throw new RuntimeException("更新的uri不合法");
        }
        database.close();
        return updateCount;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
}

注意:需要在项目中注册
<!--exported : 是否可以让其它应用访问 -->
<provider
android:authorities="com.hbwj.serviceclient.personprovider"
android:name=".PersonProvider"
android:exported="true"/>

自定义一个Resolver类:对Provide类中的数据库进行查询更新删除等操作

首先布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="insert"
        android:text="INSERT" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="delete"
        android:text="DELETE" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="update"
        android:text="UPDATE" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="query"
        android:text="QUERY" />

</LinearLayout>

查询操作

        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用query,得到cursor
        Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/1");
         uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person");
        Cursor cursor = resolver.query(uri, null, null, null, null, null);
        //3.取出其中的值并显示
        if (cursor != null) {
            while (cursor.moveToNext()) {
                int id = cursor.getInt(0);
                String name = cursor.getString(1);
                Toast.makeText(this, "id==" + id + "name==" + name, Toast.LENGTH_SHORT).show();
            }
        }

删除操作

        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用delete
        Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/1");
        int deleteCount = resolver.delete(uri, null, null);
        Toast.makeText(this, "deleteCount="+deleteCount, 1).show();

更新操作

        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用update
        Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/2");
        ContentValues values=new ContentValues();
        values.put("name","jack2");
        int updateCount = resolver.update(uri, values, null, null);
        Toast.makeText(this, "updateCount="+updateCount, Toast.LENGTH_SHORT).show();

插入操作

        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用insert
        Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person");
        ContentValues values = new ContentValues();
        values.put("name", "jack");
         uri = resolver.insert(uri, values);
        Toast.makeText(this, uri.toString(), Toast.LENGTH_SHORT).show();

案例2:选择手机联系人号码

主界面布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/et_main_number"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="请输入或选择一个联系人号码" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/et_main_number"
        android:onClick="toContactList"
        android:text="选择联系人" />

</RelativeLayout>

其他布局很简单就是一个listview去显示联系人电话号码和名字,不要问我怎么还用listview,一个字懒
主布局activity代码

 public void toContactList(View view) {
        //启动联系人列表界面
        startActivityForResult(new Intent(this, ContactListActivity.class), 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == 1 && resultCode == RESULT_OK){
            String number = data.getStringExtra("NUMBER");
            et_main_number.setText(number);
        }
            super.onActivityResult(requestCode, resultCode, data);
    }

联系人列表界面代码,adapter很简单就不粘贴了
查询联系人表数据

 ContentResolver resolver = getContentResolver();
        String[] projcetio = new String[]{
                Phone.DISPLAY_NAME,
                Phone.NUMBER
        };
        Cursor cursor = resolver.query(Phone.CONTENT_URI, projcetio, null, null, null);
        while (cursor.moveToNext()) {
            String name = cursor.getString(0);
            String number = cursor.getString(1);
            Map<String, String> map = new HashMap<>();
            map.put("name", name);
            map.put("number", number);
            data.add(map);
        }

点击某一条返回电话号码给MainActivity界面

  //得到返回的号码
        String number=data.get(position).get("number");
        Intent intent = getIntent();
        //设置结果
        intent.putExtra("NUMBER", number);
        setResult(RESULT_OK,intent);
        //返回
        finish();

**读取联系人权限**android.permission.READ_CONTACTS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值