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. 【原创】大叔问题定位分享(25)ambari metrics collector内置standalone hbase启动失败

    ambari metrics collector内置hbase目录位于 /usr/lib/ams-hbase 配置位于 /etc/ams-hbase/conf 通过ruby启动 /usr/lib/am ...

  2. 软件工程课开学测试——根据已有的CSS模板资源,搭建整个系统

    日期:2019.2.28 博客期:038 星期四 今天的测试得到了9.5分,将将及格的程度吧!本次程序完成的很不成功! <%@ page language="java" co ...

  3. Mysql索引机制(B+Tree)

    1,索引谁实现的: 索引是搜索引擎去实现的,在建立表的时候都会指定,搜索引擎是一种插拔式的,根据自己的选择去决定使用哪一个. 2,索引的定义: 索引是为了加速对表中数据行的检索而创建的一种分散存储的( ...

  4. [转]国家税务总局:个税专项附加扣除APP正式启用!(附操作指南)

    https://wallstreetcn.com/articles/3462504 12月31日国家税务总局官网消息,个人所得税专项附加扣除政策将于2019年1月1日起实施.2018年12月31日,由 ...

  5. 1002-谈谈ELK日志分析平台的性能优化理念

    在生产环境中,我们为了更好的服务于业务,通常会通过优化的手段来实现服务对外的性能最大化,节省系统性能开支:关注我的朋友们都知道,前段时间一直在搞ELK,同时也记录在了个人的博客篇章中,从部署到各个服务 ...

  6. 关于ajax请求数据,并将数据赋值给全局变量的一些解决方法

    在使用ajax请求数据是,开始的时候是打算将ajax的数据取出,并赋予给全局变量,但是在实际编码过程中发现并不能将数据赋予给最开始定义的全局变量,出现这个问题的原因是由于ajax异步加载的原因,所以只 ...

  7. c# 向数据库插数据超过1000条

    今天想着如何大批量插入数据到数据库中  最开始的想法是使用insert循环插入 但每次都要创建数据库连接 这是非常消耗时间和消耗资源的事.后在网上看到了说使用SqlBulkCopy ,就看了看文档和别 ...

  8. P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm 记忆化搜索dfs

    题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节. 由于牛棚不太大,FJ通过指定奶牛必须遵 ...

  9. 实时流式计算框架——JStorm

    1.本地调试 a.步骤:生成Topology——实现Spout接口——实现Bolt接口——编译运行 b.加入依赖 <!-- JStorm --> <dependency> &l ...

  10. python 类和元类(metaclass)的理解和简单运用

    (一) python中的类 首先这里讨论的python类,都基于继承于object的新式类进行讨论. 首先在python中,所有东西都是对象.这句话非常重要要理解元类我要重新来理解一下python中的 ...