• Android 跨进程数据共享


    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吧!

  • 相关阅读:
    Java SSM 框架相关基础面试题
    JPanel JScrollPanel
    Spring MVC 的 Converter 和 Formatter
    JDesktopPane JInternalFrames
    Spring MVC 中的 forward redirect Flash属性
    Java Swing 中使用 EventQueue
    Java 中转换为String类型的四种方法
    Eclipse 安装使用 M2Eclipse 插件
    正则表达式
    Spring MVC 数据绑定和表单标签库
  • 原文地址:https://www.cnblogs.com/oxgen/p/7879707.html
Copyright © 2020-2023  润新知