Android 开发过程中,基于功能隔离、进程安全、进程保活等等考虑,我们经常需要为应用划分进程,然后不得不面临跨进程通信和跨进程共享数据的挑战。

跨进程通信

相对来说,跨进程通信比较简单,常用的方式有:

1.全局广播

广播是最简洁的跨进程通信方式,发送——接收广播即可完成异步通信。

2.AIDL

使用AIDL进行跨进程调用、通信是不错的选择,能够支持更复杂的接口调用,通信是同步完成的。但是实现上需要与其他进程的Service建立连接,然后通过AIDL定义的接口进行调用,实现上稍显复杂。

笔者经常使用的是这两种方式,具体使用哪种看场景决定,没有最好的方案,只有最适合的方案。如果小伙伴们有更多方式,欢迎留言交流,让我也学习学习。

跨进程共享数据

跨进程共享数据也是很常见的需求,一份应用数据,各个进程都需要读取、更新使用,我们要做的就是,在各进程都可以访问到这份数据的前提下,保证数据的同步。

常用的方式有:

1.SharedPreferences

使用存储模式为MODE_MULTI_PROCESS的SharedPreferences来实现数据存储,各个进程都需要建立自己的SharedPreference实例,通过它来访问数据,系统机制保证数据的同步。不过这种方式不完全可靠,已经被官方弃用,新的Android 版本已经不再支持。

2.ContentProvider

ContentProvider是官方推荐应用间共享数据的方式,也是被大家最广泛使用的方式,由系统来保证进程间数据同步的安全性和可靠性,稳定可靠。ContentProvider提供了增删改查的接口,与数据库结合,相当于为其他进程提供了一个远程数据库,功能强大,只是实现上相当于定义了一套远程访问数据库的接口协议,稍显复杂。

3.第三方框架

常见的有github上的Tray,作为SharedPreferences跨进程版本的替代方案,使用者的反馈是不错的,不过我还没有使用研究过它:D

同样的,没有最好的方案,只有最适合的方案,使用哪一种方案,需要根据实际场景,分析各自的优点和局限性,作出合理的选择。就如同在选择使用Sqlite还是SharedPreferences的时候,对于需要复杂操作的数据,比如大量且需要复杂的增删改查的数据,应该使用Sqlite等数据库实现来存储,跨进程时就用数据库作支持的ContentProvider,对于简单的只需要简单查询,读写的数据,用SharedPreferences足矣,跨进程时,使用SharedPreferences作支持的ContentProvider足矣。

在跨进程共享简单数据,如配置、用户信息等等的时候,我常用的做法就是利用ContentProvider的跨进程安全特性,以SharedPreferences作为支撑,实现跨进程的SharedPreferences:

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils; import java.util.Iterator; /**
* Created by Irwin on 2017/8/29.
*/ public class GlobalProvider extends ContentProvider { public static final Uri AUTHORITY_URI = Uri.parse("content://[YOUR PACKAGE NAME]");
public static final Uri CONTENT_URI = AUTHORITY_URI; public static final String PARAM_KEY = "key"; public static final String PARAM_VALUE = "value"; private final String DB_NAME = "global.sp";
private SharedPreferences mStore; public static Cursor query(Context context, String... keys) {
return context.getContentResolver().query(CONTENT_URI, keys, null, null, null);
} public static String getString(Context context, String key) {
return getString(context, key, null);
} public static String getString(Context context, String key, String defValue) {
Cursor cursor = query(context, key);
String ret = defValue;
if (cursor.moveToNext()) {
ret = cursor.getString(0);
if (TextUtils.isEmpty(ret)) {
ret = defValue;
}
}
cursor.close();
return ret;
} public static int getInt(Context context, String key, int defValue) {
Cursor cursor = query(context, key);
int ret = defValue;
if (cursor.moveToNext()) {
try {
ret = cursor.getInt(0);
} catch (Exception e) { }
}
cursor.close();
return ret;
} public static Uri save(Context context, ContentValues values) {
return context.getContentResolver().insert(GlobalProvider.CONTENT_URI, values);
} public static Uri save(Context context, String key, String value) {
ContentValues values = new ContentValues(1);
values.put(key, value);
return save(context, values);
} public static Uri remove(Context context, String key) {
return save(context, key, null);
} @Override
public boolean onCreate() {
mStore = getContext().getSharedPreferences(DB_NAME, Context.MODE_PRIVATE);
return true;
} @Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
int size = projection == null ? 0 : projection.length;
if (size > 0) {
String[] values = new String[size];
for (int i = 0; i < size; i++) {
values[i] = getValue(projection[i], null);
}
return createCursor(projection, values);
}
String key = uri.getQueryParameter(PARAM_KEY);
String value = null;
if (!TextUtils.isEmpty(key)) {
value = getValue(key, null);
}
return createSingleCursor(key, value);
} protected Cursor createSingleCursor(String key, String value) {
MatrixCursor cursor = new MatrixCursor(new String[]{key}, 1);
if (!TextUtils.isEmpty(value)) {
cursor.addRow(new Object[]{value});
}
return cursor;
} protected Cursor createCursor(String[] keys, String[] values) {
MatrixCursor cursor = new MatrixCursor(keys, 1);
cursor.addRow(values);
return cursor;
} @Nullable
@Override
public String getType(@NonNull Uri uri) {
return "";
} @Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
if (values != null && values.size() > 0) {
save(values);
} else {
String key = uri.getQueryParameter(PARAM_KEY);
String value = uri.getQueryParameter(PARAM_VALUE);
if (!TextUtils.isEmpty(key)) {
save(key, value);
}
}
return null;
} @Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
String key = selection == null ? selection : uri.getQueryParameter(PARAM_KEY);
if (!TextUtils.isEmpty(key)) {
remove(key);
return 1;
}
return 0;
} @Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
if (values != null && values.size() > 0) {
save(values);
return values.size();
}
String key = uri.getQueryParameter(PARAM_KEY);
String value = uri.getQueryParameter(PARAM_VALUE);
if (!TextUtils.isEmpty(key)) {
save(key, value);
return 1;
}
return 0;
} protected String getValue(String key, String defValue) {
return mStore.getString(key, defValue);
} protected void save(ContentValues values) {
String key;
String value;
Iterator<String> iterator = values.keySet().iterator();
SharedPreferences.Editor editor = mStore.edit();
while (iterator.hasNext()) {
key = iterator.next();
value = values.getAsString(key);
if (!TextUtils.isEmpty(key)) {
if (value != null) {
editor.putString(key, value);
} else {
editor.remove(key);
}
}
}
editor.commit();
} protected void save(String key, String value) {
SharedPreferences.Editor editor = mStore.edit();
if (value != null) {
editor.putString(key, value);
} else {
editor.remove(key);
}
editor.commit();
} protected void remove(String key) {
SharedPreferences.Editor editor = mStore.edit();
editor.remove(key);
editor.commit();
} }

根据需要添加快捷访问的方法,使用起来简单方便:

//读取共享
GlobalProvider.getInt(context,PARAMETER_KEY,DEFAULT_VALUE_WHILE_NULL); //写入共享
GlobalProvider.save(context, PARAMETER_KEY, PARAMETER_VALUE);

当然,对于需要复杂操作的共享数据,还是乖乖滴基于数据库根据自己的业务需求实现完整的ContentProvider吧!

Android 跨进程数据共享的更多相关文章

  1. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

  2. Android 跨进程启动Activity黑屏(白屏)的三种解决方案

    原文链接:http://www.cnblogs.com/feidu/p/8057012.html 当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面 ...

  3. Android跨进程通信的四种方式

    由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...

  4. android 跨进程通信

    转自:http://www.androidsdn.com/article/show/137 由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一 ...

  5. 【Android跨进程】IPC总结

    前言 IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.两个进程可以是两个独立的app也可以是一个app的两个 ...

  6. android跨进程通信(IPC)——AIDL

    转载请标明出处: http://blog.csdn.net/sinat_15877283/article/details/51026711: 本文出自: [温利东的博客] 近期在看 @任玉刚 大神编写 ...

  7. Android跨进程訪问(AIDL服务)

    我将AndroidAIDL的学习知识总结一下和大家共享 在Android开发中,AIDL主要是用来跨进程訪问. Android系统中的进程之间不能共享内存,因此,须要提供一些机制在不同进程之间进行数据 ...

  8. android 跨进程通讯 AIDL

    跨进程如何通讯?两个进程无法直接通讯,通过Android系统底层间接通讯.基于service的aidl实现跨进程通讯. 什么叫AIDL? Android interface definition la ...

  9. Android跨进程通信AIDL服务

    服务(Service)是android系统中非常重要的组件.Service可以脱离应用程序运行.也就是说,应用程序只起到一个启动Service的作用.一但Service被启动,就算应用程序关闭,Ser ...

随机推荐

  1. Vue项目中,要保证某个部分的高度,应该怎么设置

    .icons overflow: hidden height: padding-bottom: % background: green

  2. appJSON["window"]["navigationBarTextStyle"] 字段需为 black 或 white

    appJSON["window"]["navigationBarTextStyle"] 字段需为 black 或 white     改动成这个就可以了 &qu ...

  3. 数字滚动特效 NumScroll

    1.使用前先引入jquery2.前端学习群:814798690 下载地址 https://github.com/chaorenzeng/jquery.numscroll.js.git 快速使用 1.引 ...

  4. 项目必备!永无 bug 注释

    佛祖保佑 永无bug 代码注释 // // _oo0oo_ // o8888888o // 88" . "88 // (| -_- |) // 0\ = /0 // ___/`-- ...

  5. Kali Linux常用服务配置教程获取IP地址

    Kali Linux常用服务配置教程获取IP地址 下面以Kali Linux为例,演示获取IP地址的方法 (1)设置网络接口为自动获取IP地址.在Kali Linux的收藏夹中单击图标,将显示所有的程 ...

  6. BZOJ.4299.Codechef FRBSUM(主席树)

    题目链接 记mx为最大的满足1~mx都能组成的数. 考虑当前能构成1~v中的所有数,再加入一个数x,若x>v+1,则mx=v,x不会产生影响:否则x<=v+1,则新的mx=x+v. 对于区 ...

  7. react中constructor()和super()的具体含义以及如何使用

    1.constructor()---super( )的基本含义 constructor()--构造方法 这是ES6对类的默认方法,通过new命令生成对象实例时自动调用该方法.并且,该方法是类中必须有的 ...

  8. Oracle 用户权限 Grant

    用户的权限来自系统权限和对象权限 一.系统权限 3个索引权限 Grant CREATE ANY INDEX to User_Name://创建索引 Grant ALTER ANY INDEX to U ...

  9. Python练手例子(3)

    13.打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数",因为153=1 ...

  10. spring boot 加载application配置文件

    这就要注意了