文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android怎么使用ContentProvider实现跨进程通讯

2023-07-05 10:37

关注

这篇“Android怎么使用ContentProvider实现跨进程通讯”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android怎么使用ContentProvider实现跨进程通讯”文章吧。

1 前言

ContentProvider 即内容提供器,是 Android 四大组件之一,为 App 存取数据提供统一的对外接口,让不同的应用之间可以共享数据。

如图,Server 端通过 ContentProvider 对外提供操作本地数据(DataBase、File 等)的接口,Client 端通过 ContentResolver 与 ContentProvider 通讯,从而实现跨进程操作 Server 端数据,Observer 端通过 ContentObserver 监听 Server 端的数据是否发生变化,并触发相关操作。

Android怎么使用ContentProvider实现跨进程通讯

(1) ContentProvider 接口

ContentProvider 是一个抽象类,用户需要实现如下抽象方法。

// 创建数据库并获得数据库连接public abstract boolean onCreate()// 查询数据public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)// 插入数据public abstract Uri insert(Uri uri, ContentValues values)// 删除数据public abstract int delete(Uri uri, String selection, String[] selectionArgs)// 更新数据public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)// 获取数据类型(MIME类型,如:"text/html"、"image/png"、"message/rfc882"、"vnd.android-dir/mms-sms")public abstract String getType(Uri uri)

参数说明:

(2)ContentResolver 接口

// 查询数据public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)// 插入数据public final Uri insert(Uri url, ContentValues values)// 删除数据public final int delete(Uri url, String selection, String[] selectionArgs)// 更新数据public final int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

可以看到,ContentProvider 和 ContentResolver 都有增删改查操作,并且参数列表完全一致,以实现对 Server 端数据的操作。

(3)ContentObserver 接口

ContentObserver 是一个抽象类,用户需要重写其构造方法和 onChange() 方法。

//用户需要重写构造方法,并注入 handlerpublic ContentObserver(Handler handler)//监听的内容发生变化时调用public void onChange(boolean selfChange)//注册 ContentObservermContext.getContentResolver().registerContentObserver(uri, false, observer);//注销 ContentObservermContext.getContentResolver().unregisterContentObserver(observer);

2 URI 简介

URI 即统一资源标识符(Uniform Resource Identifier),能够唯一标识资源,如同资源的身份ID。数据库的 URI 在 ContentProvider 中定义,ContentResolver 通过资源 URI 找到对应的 ContentProvider,从而操作数据库。URI 类图如下。

Android怎么使用ContentProvider实现跨进程通讯

URI 由3部分组成:scheme、authority、path,其中 authority 又由 host、port 组成,URI 一般格式如下:

scheme://authority/path?queryscheme://host:port/path?query

URI 类的常用接口如下:

//根据 uriString 生成 StringUri 对象(Uri的子类,重写了Uri的抽象方法)public static Uri parse(String uriString)//根据 fiel 生成 HierarchicalUri 对象(Uri的子类,重写了Uri的抽象方法)public static Uri fromFile(File file)//根据 scheme、ssp、fragment 生成 OpaqueUri 对象(Uri的子类,重写了Uri的抽象方法)public static Uri fromParts(String scheme, String ssp, String fragment)public abstract String getScheme()public abstract String getHost()public abstract int getPort()public abstract String getPath()public abstract String getQuery()

常见的 URI 实例如下:

//网络资源https://blog.csdn.net/m0_37602827//本地资源file:///sdcard/Pictures/WeiXin/a.mp4//ContentProvidercontent://com.zhyan8.content.MyProvider/query//打电话tel:10086//发短信smsto:10086//发邮件mailto:xxxx@qq.com//定位geo:52.76,-79.0342

3 项目结构

本文将以一个案例讲解使用 ContentProvider 实现跨进程通讯,项目结构如下,一共包含 3 个 Module。

Android怎么使用ContentProvider实现跨进程通讯

Android怎么使用ContentProvider实现跨进程通讯

4 服务端(Content_S)

(1)数据库操作类

DBHelper.java

package com.zhyan8.content_s;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DBHelper extends SQLiteOpenHelper {    private static final String DATABASE = "test.db";    private static final String TABLE = "user";    public DBHelper(Context context) {        super(context, DATABASE, null, 1);    }    @Override    public void onCreate(SQLiteDatabase db) {        String create_table = "create table " + TABLE + "(id int primary key, name varchar not null)";        db.execSQL(create_table);        db.execSQL("insert into " + TABLE + " values(1001, '张三'),(1002, '李四')");    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}    public Cursor query() {        SQLiteDatabase db = getReadableDatabase();        String sql = "select * from " + TABLE;        Cursor cursor = db.rawQuery(sql, null);        return cursor;    }    public long insert(ContentValues cv) {        SQLiteDatabase db = getWritableDatabase();        long result = db.insert(TABLE, null, cv);        db.close();        return result;    }}

生成的数据库如下:

Android怎么使用ContentProvider实现跨进程通讯

(2)自定义 ContentProvider

MyProvider.java

package com.zhyan8.content_s;import android.content.ContentProvider;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.net.Uri;import android.util.Log;public class MyProvider extends ContentProvider {    private DBHelper mUserDBHelper;    private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //用于匹配URI,并返回对应的操作编码    private static final String AUTHORITES = "com.zhyan8.content.MyProvider";    private static final int QUERY = 1; //查询操作编码    private static final int INSERT = 2; //插入操作编码    static { //添加有效的 URI 及其编码        sUriMatcher.addURI(AUTHORITES, "/query", QUERY);        sUriMatcher.addURI(AUTHORITES, "/insert", INSERT);    }    @Override    public boolean onCreate() {        mUserDBHelper = new DBHelper(getContext());        return false;    }    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        Log.e("xxx-Provider", "query: ");        int code = sUriMatcher.match(uri);        if (code == QUERY) {            return mUserDBHelper.query();        }        return null;    }    @Override    public Uri insert(Uri uri, ContentValues values) {        Log.e("xxx-Provider", "insert: ");        int code = sUriMatcher.match(uri);        if (code == INSERT) {            mUserDBHelper.insert(values);        }        getContext().getContentResolver().notifyChange(uri, null); //通知外界,数据发生变化        return null;    }    @Override    public String getType(Uri uri) { //获取资源 MIME        return null;    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        return 0;    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        return 0;    }}

(3)配置

在 AndroidManifest.xml 的 application 节点下配置 ContentProvider,如下。

<provider      android:name=".MyProvider"      android:authorities="com.zhyan8.content.MyProvider"      android:exported="true" />

exported 属性用于定义是否允许外界访问。

(4)主类

MainActivity.java

package com.zhyan8.content_s;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

5 客户端(Content_C)

(1)数据类

User.java

package com.zhyan8.content_c;public class User {    private Integer id;    private String name;    public User(){};    public User(Integer id, String name) {        this.id = id;        this.name = name;    }    public void setId(Integer id) {        this.id = id;    }    public void setName(String name) {        this.name = name;    }    public Integer getId() {        return id;    }    public String getName() {        return name;    }    @Override    public String toString() {        return "User{" + "id=" + id + ", name='" + name + '\'' + '}';    }}

(2)自定义 ContentResolver

MyResolver.java

package com.zhyan8.content_c;import android.content.ContentResolver;import android.content.ContentValues;import android.content.Context;import android.database.ContentObserver;import android.database.Cursor;import android.net.Uri;import java.util.ArrayList;public class MyResolver {    private ContentResolver mContentResolver;    private static final String AUTHORITES = "com.zhyan8.content.MyProvider";    public MyResolver(Context context) {        mContentResolver = context.getContentResolver();    }    public ArrayList<User> query() {        ArrayList<User> list = new ArrayList<>();        Uri uri = Uri.parse("content://" + AUTHORITES + "/query");        Cursor cursor = mContentResolver.query(uri, null, null, null, null);        while (cursor.moveToNext()) {            User user = new User();            user.setId(cursor.getInt(0));            user.setName(cursor.getString(1));            list.add(user);        }        cursor.close();        return list;    }    public void insert(User user) {        Uri uri = Uri.parse("content://" + AUTHORITES + "/insert");        ContentValues cv = new ContentValues();        cv.put("id", user.getId());        cv.put("name", user.getName());        mContentResolver.insert(uri, cv);    }}

(3)主类

MainActivity.java

package com.zhyan8.content_c;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import java.util.ArrayList;public class MainActivity extends AppCompatActivity {    private MyResolver myResolver;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        myResolver = new MyResolver(this);    }    public void clickQuery(View v) {        ArrayList<User> users = myResolver.query();        Log.e("xxx", "clickQuery: " + users.toString());    }    public void clickInsert(View v) {        User user = new User(1003, "王五");        myResolver.insert(user);    }}

(4)布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout    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"    tools:context=".MainActivity"    android:orientation="vertical">    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="查询"        android:textSize="40sp"        android:layout_marginTop="50dp"        android:onClick="clickQuery"/>    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="添加"        android:textSize="40sp"        android:layout_marginTop="50dp"        android:onClick="clickInsert"/></LinearLayout>

界面如下:

Android怎么使用ContentProvider实现跨进程通讯

5 监听者(Content_O)

(1)自定义 ContentObserver

MyObserver.java

package com.zhyan8.content_o;import android.database.ContentObserver;import android.os.Handler;public class MyObserver extends ContentObserver {    private Uri mUri = Uri.parse("content://com.zhyan8.content.MyProvider/insert");    private ContentResolver mResolver;    Handler mHandler;    public MyObserver(Context context, Handler handler) {        super(handler);        mResolver = context.getContentResolver();        mHandler = handler;    }    @Override    public void onChange(boolean selfChange) {        mHandler.sendEmptyMessage(0x111);    }    public void registerObserver() {        mResolver.registerContentObserver(mUri, false, this);    }    public void unregisterObserver() {        mResolver.unregisterContentObserver(this);    }}

(2)主类

MainActivity.java

package com.zhyan8.content_o;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class MainActivity extends AppCompatActivity {    private MyObserver mObserver;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mObserver = new MyObserver(mHandler);        mObserver.registerObserver();    }    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            if (msg.what==0x111) {                Log.e("xxx", "监听的数据改变了");            }        }    };    @Override    public void onDestroy() {        mObserver.unregisterObserver();        super.onDestroy();    }}

6 效果展示

首先保证 Content_S、Content_C 和 Content_O 3个应用都打开了,再在 Content_C 端依次点击【查询】&rarr;【插入】&rarr;【查询】,打印日志如下:

2020-11-22 22:47:41.397 5227-5597/com.zhyan8.content_s E/xxx-Provider: query:     
2020-11-22 22:47:41.401 6261-6261/com.zhyan8.content_c E/xxx: clickQuery: [User{id=1001, name='张三'}, User{id=1002, name='李四'}]
2020-11-22 22:47:49.848 5227-5493/com.zhyan8.content_s E/xxx-Provider: insert: 
2020-11-22 22:47:49.855 7879-7879/com.zhyan8.content_o E/xxx: 监听的数据改变了
2020-11-22 22:47:52.055 5227-5597/com.zhyan8.content_s E/xxx-Provider: query: 
2020-11-22 22:47:52.063 6261-6261/com.zhyan8.content_c E/xxx: clickQuery: [User{id=1001, name='张三'}, User{id=1002, name='李四'}, User{id=1003, name='王五'}]

以上就是关于“Android怎么使用ContentProvider实现跨进程通讯”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯