标签:color 个性化定制 launcher attach 需求 csdn 对象 而在 tap
/** * Created by jesse on 15-7-17. */ public class MyApplication extends Application{ private final String TAG = MyApplication.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); Log.i(TAG + ", onCreate " + this.getApplicationContext().getClass().getSimpleName()); } }而且在DeskClock的入口Activity,DeskClock处也print出该程序眼下ApplicationContext的名字用于兴许Proxy后的对照.
<application android:name="cn.jesse.MyApplication" android:label="@string/app_label" android:icon="@mipmap/ic_launcher_alarmclock" android:requiredForAllUsers="true" android:supportsRtl="true">过滤后的执行Log: 简单的流程就是先启动自己定义MyApplication 之后再launch DeskClock,同一时候都打印出来ApplicationContext的名字
<application android:name="cn.jesse.MyProxyApplication" android:label="@string/app_label" android:icon="@mipmap/ic_launcher_alarmclock" android:requiredForAllUsers="true" android:supportsRtl="true"> <meta-data android:name="DELEGATE_APPLICATION_CLASS_NAME" android:value="cn.jesse.MyApplication" > </meta-data> </application>
* Created by jesse on 15-7-17. */ public abstract class ProxyApplication extends Application{ protected abstract void initProxyApplication(); }当我们要替换当前ProxyApplication的ClassLoader为父类的ClassLoader,所以这个替换的动作要足够得早(要保证在app Context最早被构建的入口处替换ClassLoader),要不然就会出现替换不干净的情况,就会有程序中大部分使用的DelegateApplication的ClassLoader,而一小部分是使用的ProxyApplication的ClassLoader,这样可能会出现一些意想不到的bug.
/** * Set the base context for this ContextWrapper. All calls will then be * delegated to the base context. Throws * IllegalStateException if a base context has already been set. * * @param base The new base context for this wrapper. */ protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; }转换ClassLoader的入口也确定之后就能够自己定义一个MyProxyApplication,继承自ProxyApplication而且复写attachBaseContext方法,print相关信息
/** * Created by jesse on 15-7-17. */ public class MyProxyApplication extends ProxyApplication { private final String TAG = MyProxyApplication.class.getSimpleName(); private Context mContext; @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); Log.i(TAG + ", attachBaseContext"); mContext = base; this.initProxyApplication(); } @Override public void onCreate() { super.onCreate(); Log.i(TAG + ", onCreate" + this.getApplicationContext().getClass().getSimpleName()); BootLoader.boot(mContext); } @Override protected void initProxyApplication() { Log.i(TAG + ", initProxyApplication"); BootLoader.resetClassLoader(mContext); } }Log执行的顺序,先进入attachBaseContext->initProxyApplication->onCreate->DeskClock:onCreate (这里DeskClock的onCreate获取到的ApplicationContext的名字是(MyProxyApplication)
String className = CLASS_NAME; ApplicationInfo appInfo = getPackageManager().getApplicationInfo(super.getPackageName(), PackageManager.GET_META_DATA); Bundle bundle = appInfo.metaData; if (bundle != null && bundle.containsKey(KEY)) { className = bundle.getString(KEY); if (className.startsWith(".")) className = super.getPackageName() + className; }依据className反射得到MyApplication,创建MyApplication实例而且取得MyProxyApplication的实例
Class delegateClass = Class.forName(className, true, getClassLoader()); Application delegate = (Application) delegateClass.newInstance(); Application proxyApplication = (Application)getApplicationContext();使用反射更换MyProxyApplication context成员中的mOuterContext属性
Class contextImplClass = Class.forName("android.app.ContextImpl"); Field mOuterContext = contextImplClass.getDeclaredField("mOuterContext"); mOuterContext.setAccessible(true); mOuterContext.set(mContext, delegate);
Field mPackageInfoField = contextImplClass.getDeclaredField("mPackageInfo"); mPackageInfoField.setAccessible(true); Object mPackageInfo = mPackageInfoField.get(mContext); Class loadedApkClass = Class.forName("android.app.LoadedApk"); Field mApplication = loadedApkClass.getDeclaredField("mApplication"); mApplication.setAccessible(true); mApplication.set(mPackageInfo, delegate);
Class activityThreadClass = Class.forName("android.app.ActivityThread"); Field mAcitivityThreadField = loadedApkClass.getDeclaredField("mActivityThread"); mAcitivityThreadField.setAccessible(true); Object mActivityThread = mAcitivityThreadField.get(mPackageInfo); Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication"); mInitialApplicationField.setAccessible(true); mInitialApplicationField.set(mActivityThread, delegate);
Field mAllApplicationsField = activityThreadClass.getDeclaredField("mAllApplications"); mAllApplicationsField.setAccessible(true); ArrayList<Application> al = (ArrayList<Application>)mAllApplicationsField.get(mActivityThread); al.add(delegate); al.remove(proxyApplication);
Method attach = Application.class.getDeclaredMethod("attach", Context.class); attach.setAccessible(true); attach.invoke(delegate, mContext); delegate.onCreate();完毕这些步骤之后再又一次执行查看Log,观察DeskClock处获取的ApplicationContext的名字已经变成MyApplication.
private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; IContentProvider provider; if (holder == null || holder.provider == null) { if (DEBUG_PROVIDER || noisy) { Slog.d(TAG, "Loading provider " + info.authority + ": " + info.name); } Context c = null; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { c = mInitialApplication; } else { try { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } }
转载请注明出处:http://blog.csdn.net/l2show/article/details/46914881
Android源代码之DeskClock (三) Proxy/Delegate Application 框架应用
标签:color 个性化定制 launcher attach 需求 csdn 对象 而在 tap
原文地址:http://www.cnblogs.com/jzdwajue/p/7123677.html