Xposed 利用ContentProvider实现跨进程数据读取

Xposed 利用ContentProvider实现跨进程数据读取

由于Android N以后,Sharepreference的第三个参数MODE_WORLD_READABLE的被禁止,Shareperference的跨进程通信变得不可用,谷歌推荐使用ContentProvider进行通信。

但是由于ContentProvider在平时简单的使用中过于重量,需要进行数据库操作特别的麻烦,所以我找到了一个库,基于ContentProvider封装,使用和平时SharePreference基本一致。

开源库地址:MultiprocessSharedPreferences

关键库代码:MultiprocessSharedPreferences.java

/*
 * 创建日期:2014年9月12日 下午0:0:02
 */
package com.android.zgj.utils;

import com.android.zgj.BuildConfig;

import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.UriMatcher;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.support.annotation.NonNull;
import android.util.Log;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

/**
 * 使用ContentProvider实现多进程SharedPreferences读写;<br>
 * 1、ContentProvider天生支持多进程访问;<br>
 * 2、使用内部私有BroadcastReceiver实现多进程OnSharedPreferenceChangeListener监听;<br>
 * 
 * 使用方法:AndroidManifest.xml中添加provider申明:<br>
 * <pre>
 * &lt;provider android:name="com.android.zgj.utils.MultiprocessSharedPreferences"
 * android:authorities="com.android.zgj.MultiprocessSharedPreferences"
 * android:process="com.android.zgj.MultiprocessSharedPreferences"
 * android:exported="false" /&gt;
 * &lt;!-- authorities属性里面最好使用包名做前缀,apk在安装时authorities同名的provider需要校验签名,否则无法安装;--!/&gt;<br>
 * </pre>
 * 
 * ContentProvider方式实现要注意:<br>
 * 1、当ContentProvider所在进程android.os.Process.killProcess(pid)时,会导致整个应用程序完全意外退出或者ContentProvider所在进程重启;<br>
 * 重启报错信息:Acquiring provider <processName> for user 0: existing object's process dead;<br>
 * 2、如果设备处在“安全模式”下,只有系统自带的ContentProvider才能被正常解析使用,因此put值时默认返回false,get值时默认返回null;<br>
 * 
 * 其他方式实现SharedPreferences的问题:<br>
 * 使用FileLock和FileObserver也可以实现多进程SharedPreferences读写,但是维护成本高,需要定期对照系统实现更新新的特性;
 * 
 * @author zhangguojun
 * @version	1.0
 * @since JDK1.6
 */
public class MultiprocessSharedPreferences extends ContentProvider implements SharedPreferences {
	private static final String TAG = "MultiprocessSharedPreferences";
	public static final boolean DEBUG = BuildConfig.DEBUG;
	private Context mContext;
	private String mName;
	private int mMode;
	private boolean mIsSafeMode;
	private static final Object CONTENT = new Object();
	private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
	private BroadcastReceiver mReceiver;

	private static String AUTHORITY;
	private static volatile Uri AUTHORITY_URI;
	private UriMatcher mUriMatcher;
	private static final String KEY = "value";
	private static final String KEY_NAME = "name";
	private static final String PATH_WILDCARD = "*/";
	private static final String PATH_GET_ALL = "getAll";
	private static final String PATH_GET_STRING = "getString";
	private static final String PATH_GET_INT = "getInt";
	private static final String PATH_GET_LONG = "getLong";
	private static final String PATH_GET_FLOAT = "getFloat";
	private static final String PATH_GET_BOOLEAN = "getBoolean";
	private static final String PATH_CONTAINS = "contains";
	private static final String PATH_APPLY = "apply";
	private static final String PATH_COMMIT = "commit";
	private static final String PATH_REGISTER_ON_SHARED_PREFERENCE_CHANGE_LISTENER = "registerOnSharedPreferenceChangeListener";
	private static final String PATH_UNREGISTER_ON_SHARED_PREFERENCE_CHANGE_LISTENER = "unregisterOnSharedPreferenceChangeListener";
	private static final String PATH_GET_STRING_SET = "getStringSet";
	private static final int GET_ALL = 1;
	private static final int GET_STRING = 2;
	private static final int GET_INT = 3;
	private static final int GET_LONG = 4;
	private static final int GET_FLOAT = 5;
	private static final int GET_BOOLEAN = 6;
	private static final int CONTAINS = 7;
	private static final int APPLY = 8;
	private static final int COMMIT = 9;
	private static final int REGISTER_ON_SHARED_PREFERENCE_CHANGE_LISTENER = 10;
	private static final int UNREGISTER_ON_SHARED_PREFERENCE_CHANGE_LISTENER = 11;
	private static final int GET_STRING_SET = 12;
	private HashMap<String, Integer> mListenersCount;

	private static class ReflectionUtil {

		public static ContentValues contentValuesNewInstance(HashMap<String, Object> values) {
			try {
				Constructor<ContentValues> c = ContentValues.class.getDeclaredConstructor(new Class[] { HashMap.class }); // hide
				c.setAccessible(true);
				return c.newInstance(values);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			} catch (InstantiationException e) {
				throw new RuntimeException(e);
			}
		}

		public static Editor editorPutStringSet(Editor editor, String key, Set<String> values) {
			try {
				Method method = editor.getClass().getDeclaredMethod("putStringSet", new Class[] { String.class, Set.class }); // Android 3.0
				return (Editor) method.invoke(editor, key, values);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}

		@SuppressWarnings("unchecked")
		public static Set<String> sharedPreferencesGetStringSet(SharedPreferences sharedPreferences, String key, Set<String> values) {
			try {
				Method method = sharedPreferences.getClass().getDeclaredMethod("getStringSet", new Class[] { String.class, Set.class }); // Android 3.0
				return (Set<String>) method.invoke(sharedPreferences, key, values);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
		}

		public static void editorApply(Editor editor) {
			try {
				Method method = editor.getClass().getDeclaredMethod("apply"); // Android 2.3
				method.invoke(editor);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} c
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值