Android动态加载Activity原理

本文介绍了Android动态加载Activity的原理,包括活动的启动流程和动态加载的两种方法:修改系统类加载器和使用代理。在修改系统类加载器的方法中,通过替换默认的PathClassLoader以加载插件中的Activity,解决了找不到类的问题。而使用代理的方式,通过一个代理Activity管理插件Activity的生命周期,避免了在AndroidManifest中声明大量插件Activity。
摘要由CSDN通过智能技术生成

activity的启动流程

加载一个Activity肯定不会像加载一般的类那样,因为activity作为系统的组件有自己的生命周期,有系统的很多回调控制,所以自定义一个DexClassLoader类加载器来加载插件中的Activity肯定是不可以的。

首先不得不了解一下activity的启动流程,当然只是简单的看一下,太详细的话很难研究清楚。

通过startActivity启动后,最终通过AMS进行跨进程回调到ApplicationThread的scheduleLaunchActivity,这时会创建一个ActivityClientRecord对象,这个对象表示一个Acticity以及他的相关信息,比如activityInfo字段包括了启动模式等,还有loadedApk,顾名思义指的是加载过了的APK,他会被放在一个Map中,应用包名到LoadedApk的键值对,包含了一个应用的相关信息。然后通过Handler切换到主线程执performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    // 1.创建ActivityClientRecord对象时没有对他的packageInfo赋值,所以它是null
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);
    }
    // ...
    Activity activity = null;
    try {
    	// 2.非常重要!!这个ClassLoader保存于LoadedApk对象中,它是用来加载我们写的activity的加载器
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        // 3.用加载器来加载activity类,这个会根据不同的intent加载匹配的activity
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
    	// 4.这里的异常也是非常非常重要的!!!后面就根据这个提示找到突破口。。。
        if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
    }
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            // 从这里就会执行到我们通常看到的activity的生命周期的onCreate里面
            mInstrumentation.callActivityOnCreate(activity, r.state);
            // 省略的是根据不同的状态执行生命周期
        }
        r.paused = true;
        mActivities.put(r.token, r);
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
    	// ...
    }
    return activity;
}

1.getPackageInfo方法最终返回一个LoadedApk对象,它会从一个HashMap的数据结构中取,mPackages维护了包名和LoadedApk的对应关系,即每一个应用有一个键值对对应。如果为null,就新创建一个LoadedApk对象,并将其添加到Map中,重点是这个对象的ClassLoader字段为null!

    public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
            int flags) {
    	// 为true
        boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
        boolean securityViolation = includeCode && ai.uid != 0
                && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
                        ? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
                        : true);
		// ...
        // includeCode为true
        // classloader为null!!!
        return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
    }

    private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
        synchronized (mPackages) {
            WeakReference<LoadedApk> ref;
            if (includeCode) {
            	// includeCode为true
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }
            LoadedApk packageInfo = ref != null ? ref.get() : null;
            if (packageInfo == null || (packageInfo.mResources != null && !packageInfo.mResources.getAssets().isUpToDate())) {
                if (localLOGV) // ...
                // packageInfo为null,创建一个LoadedApk,并且添加到mPackages里面
                packageInfo = new LoadedApk(this, aInfo, compatInfo, this, baseLoader, securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo. ) != 0);
                if (includeCode) {
                    mPackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
                }
            }
            return packageInfo;
        }
    }

2.获取这个activity对应的类加载器,由于上面说过,mClassLoa

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值