0329-ContentProvider和ContentResolver

本文介绍Android中的ContentProvider和ContentResolver,解释如何通过它们实现应用间数据共享。文章详细阐述了ContentProvider的工作原理及其与ContentResolver的配合使用,并通过具体实例展示了如何搭建简单的数据共享系统。
一、什么是ContentProvider?

ContentProvider在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。

ContentProvider是Android中的四大组件之一,可以将应用中的数据对外进行共享

ContentProvider将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略

ContentProvider将数据封装,只暴露出我们希望提供给其他程序的数据

ContentProvider中数据更改可被监听

二、什么是ContentResolver?

ContentResolver是数据调用者,ContentProvider将数据发布出来后,通过ContentResolver对象结合Uri进行使用

通过ContentResolver可以调用ContentProvider的增、删、改、查操作

三、为什么要学习ContentProvider&ContentResolver?

1.多媒体数据库专门存储手机中的图片、音频、视频的媒体信息
2.当我们想获得手机中的音频信息时,不使用多媒体数据库、我们只能全盘递归,来寻找所需的音频信息
3.Android系统通过ContentProvider将多媒体数据共享出来、其他APP(调用者)只通过ContentResolver获取所需数据即可

四、什么是Uri?

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
Uri写法:content://com.android.contacts/contacts
content:此部分是固定写法,用来表明这是一个Uri
com.android.contacts:此部分指定了要访问的资源的存放地址即包名
contacts:此部分指定了要访问资源的路径

五、ContentProvider、ContentResolver用法:
  1. 使用SQLite技术、创建好数据库和数据表;
  2. 新建类继承ContentProvider;
  3. 创建UriMacther定义Uri规则;
  4. 重写六个抽象方法
  5. 在AndroidManifest中注册provider
  6. ContentResolver对ContentProvider共享的数据进行增、删、改、查
六 、ContentProvider&ContentResolver使用实例:

使用ContentProvider和ContentResolver进行跨进程通信。
1.新建一个工程project,创建数据库,新建一个DataBaseProvider 继承ContentProvider。重写里面的六个方法:

package com.test.project.myapplication;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

public class DataBaseProvider extends ContentProvider {
    public static final int STUDENT_DIR = 0;
    public static final int STUDENT_ITEM = 1;
    public static final String AUTHORITY = "com.test.project.myapplication";
    private static UriMatcher uriMatcher;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
        uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
    }

    private MyDataBaseHelper dbHelper;

    public DataBaseProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Implement this to handle requests to delete one or more rows.
        dbHelper = new MyDataBaseHelper(getContext(), "Student.db", null, 2);
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.delete("student",selection,selectionArgs);
        return 1;
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
                return "vnd.android.cursor.dir/vnd.com.test.project.myapplication.student";
            case STUDENT_ITEM:
                return "vnd.android.cursor.item/vnd.com.test.project.myapplication.student";
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO: Implement this to handle requests to insert a new row.
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
            case STUDENT_ITEM:
                long newStudentId = db.insert("student", null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/student/" + newStudentId);
                break;


        }
        return uriReturn;
    }

    @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        dbHelper = new MyDataBaseHelper(getContext(), "Student.db", null, 2);
        Log.e("onCreate: ", "-----------------------");

        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        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;
            default:
                break;

        }
//        Log.e("query: ", "-----------------------");
        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.

        SQLiteDatabase db=dbHelper.getWritableDatabase();
        int updateRows=0;
        switch (uriMatcher.match(uri)){
            case STUDENT_DIR:
                updateRows=db.update("student",values,selection,selectionArgs);
                break;
            case STUDENT_ITEM:
                updateRows=db.update("student",values,selection,selectionArgs);
                break;
                default:
                    break;
        }
        return updateRows;
    }
}

2.新建一个工程project,布置其MainActivity代码。
在MainActivity.java中通过Button点击事件使用ContentResolver获取上面建好的project的数据
代码如下:

public class Main1Activity extends AppCompatActivity implements View.OnClickListener {

    private Button queryBtn;
    private Button insertBrn;
    private Button updateBtn;
    private Button deleteBtn;

    private EditText inputEd;
    private EditText inputEd2;

    private String newId;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);
        bindId();

    }

    private void bindId() {
        queryBtn=findViewById(R.id.query_res_btn);
        insertBrn=findViewById(R.id.insert_res_btn);
        updateBtn=findViewById(R.id.update_res_btn);
        deleteBtn=findViewById(R.id.delete_res_btn);
        inputEd=findViewById(R.id.input_ed);
        inputEd2=findViewById(R.id.input_ed2);


        queryBtn.setOnClickListener(this);
        insertBrn.setOnClickListener(this);
        updateBtn.setOnClickListener(this);
        deleteBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.query_res_btn:
                //查询数据
                Uri uri1=Uri.parse("content://com.test.project.myapplication/student");
                Cursor cursor=getContentResolver().query(uri1,null,null,null,null);
                if (cursor!=null){
                    while (cursor.moveToNext()){
                        String name=cursor.getString(cursor.getColumnIndex("name"));
                        Log.e( "name: ",name );
                    }
                    cursor.close();
                }
                break;
            case R.id.insert_res_btn:
                //插入数据
                String name=inputEd.getText().toString();
                Uri uri2=Uri.parse("content://com.test.project.myapplication/student");
                ContentValues values=new ContentValues();
                values.put("name",name);
                Uri newUri=getContentResolver().insert(uri2,values);
                newId=newUri.getPathSegments().get(1);
                break;
            case R.id.update_res_btn:
                //修改数据
                Uri uri3=Uri.parse("content://com.test.project.myapplication/student");
                String newd=inputEd.getText().toString();
                String old=inputEd2.getText().toString();
                ContentValues values1=new ContentValues();
                values1.put("name",newd);
                getContentResolver().update(uri3,values1,"name=?",new String[]{old});
                break;
            case R.id.delete_res_btn:
             //删除数据
                String deld=inputEd.getText().toString();
                Uri uri4=Uri.parse("content://com.test.project.myapplication/student"+newId);
                ContentResolver resolver=getContentResolver();
                resolver.delete(uri4,"name=?",new String[]{deld});
                break;
        }
    }
}
<think> 我们正在讨论ContentProviderContentResolver的区别。根据用户提供的引用之前的问题,我们需要明确两者的角色功能差异。 引用[1]提到:ContentResolver根据内容标识找到对应的ContentProvider,从而实现应用数据的存取。每次通过ContentResolver调用方法(如query、update)时,都会解析URI并寻找对应的ContentProvider,这个过程是耗资源的。另外,连接断开ContentProvider也很耗资源。 引用[2]提到:ContentProvider屏蔽了数据存储的细节,用户只需关心URI;它还能实现不同app的数据共享,而数据库只能被自己的程序访问;此外,ContentProvider还能增删本地文件、xml等信息。 现在,我们重点区分ContentProviderContentResolver: 1. **ContentProvider**: - 是一个数据提供者,负责管理对结构化数据集的访问。 - 封装数据并提供统一的接口(CRUD操作)来访问数据,无论数据存储在何处(数据库、文件、网络等)。 - 允许不同应用程序之间共享数据(通过URI机制)。 - 需要实现`query()`, `insert()`, `update()`, `delete()`, `getType()`, `onCreate()`等方法。 2. **ContentResolver**: - 是客户端用来与ContentProvider通信的对象。 - 在客户端(如Activity、Service)中,通过ContentResolver调用ContentProvider提供的方法(如query, insert, update, delete)。 - 它处理与ContentProvider的通信,包括通过URI找到正确的ContentProvider,并将请求分发到对应的方法。 - 由于ContentResolver可以管理多个ContentProvider的请求,它提供了一层抽象,客户端无需关心具体的ContentProvider实现。 **关键区别**: - ContentProvider数据的提供者,而ContentResolver数据的访问者(客户端代理)。 - 应用程序通过ContentResolverContentProvider发送请求,ContentResolver负责解析URI并找到对应的ContentProvider,然后调用其方法。 **类比**: -ContentProvider看作是一个餐厅(提供食物),ContentResolver就是外卖小哥(帮助顾客从餐厅获取食物)。顾客(客户端)只需要告诉外卖小哥(ContentResolver)要什么(URI),外卖小哥就会找到对应的餐厅(ContentProvider)并取回食物(数据)。 **性能注意**: - 每次通过ContentResolver访问ContentProvider时,都需要解析URI并建立连接,这是耗资源的。因此,如果频繁操作,可以考虑使用`ContentProviderClient`(在同一个应用中)来复用连接,减少开销(引用[1]提到连接断开很耗资源,但未明确说明是否可以回收利用,实际上可以通过`ContentProviderClient`进行连接复用)。 **总结**: - ContentProvider数据提供端,实现数据访问接口。 - ContentResolver:客户端使用,作为中间层调用ContentProvider。 现在按照要求生成回答,并使用LaTeX格式(如果有数学表达式的话,但本问题可能没有,所以主要用文字描述),最后生成相关问题。 </think> ### ContentProviderContentResolver 的区别解析 #### 1. **核心角色定位** | **组件** | **角色** | **类比说明** | |------------------|-----------------------------|----------------------------------| | **ContentProvider** | 数据提供者 | 类似餐厅(提供数据食物)[^2] | | **ContentResolver** | 数据访问中介 | 类似外卖平台(连接用户与餐厅)[^1] | #### 2. **核心功能差异** $$ \begin{array}{|c|c|c|} \hline \text{功能维度} & \text{ContentProvider} & \text{ContentResolver} \\ \hline \text{数据存储} & \text{实际管理数据存储(数据库/文件等)} & \text{不存储数据,仅访问接口} \\ \hline \text{URI处理} & \text{声明自身URI(如 content://com.xx.provider)} & \text{解析URI并路由到对应Provider} \\ \hline \text{跨应用共享} & \text{提供跨应用数据共享能力 [^2]} & \text{作为客户端调用入口} \\ \hline \text{资源消耗} & \text{连接建立后可持续服务} & \text{每次操作都需重新查找Provider(高开销)[^1]} \\ \hline \end{array} $$ #### 3. **交互流程示例** ```mermaid sequenceDiagram participant 客户端App participant ContentResolver participant ContentProvider 客户端App->>ContentResolver: query(URI, ...) ContentResolver->>系统服务: 解析URI确定目标Provider 系统服务-->>ContentResolver: 返回匹配的Provider ContentResolver->>ContentProvider: 转发query请求 ContentProvider->>数据库: 执行实际查询 数据-->>ContentProvider: 返回结果集 ContentProvider-->>ContentResolver: 返回Cursor ContentResolver-->>客户端App: 返回Cursor ``` #### 4. **关键区别详解** 1. **数据访问方式** - ContentProvider: 实现数据操作接口(CRUD),如: ```java public Cursor query(Uri uri, String[] projection, String selection, ...) ``` - ContentResolver: **代理调用**Provider的接口,如: ```java getContentResolver().query(uri, projection, selection, ...) ``` 2. **URI处理机制** - Provider 声明可处理的URI路径(在AndroidManifest.xml注册) - Resolver 通过URI的**authority**部分(如`com.xx.provider`)定位Provider[^1] 3. **性能影响** ContentResolver每次操作需完成: $$ \text{查找耗时} = T_{\text{URI解析}} + T_{\text{Provider绑定}} $$ 因此频繁操作时建议通过`ContentProviderClient`复用连接[^1] #### 5. **设计哲学** | **原则** | ContentProvider体现 | ContentResolver体现 | |-------------------|----------------------------------------|----------------------------------| | **封装性** | 隐藏数据存储细节(SQLite/文件等)[^2] | 隐藏Provider定位细节 | | **单一职责** | 专注数据管理 | 专注请求路由 | | **跨进程通信** | 通过Binder暴露接口 | 封装IPC调用细节 | > 💡 **本质区别**: > ContentProvider = **数据源**(定义"如何存取") > ContentResolver = **路由代理**(解决"去哪里存取")
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值