谈谈Application的作用与启动流程

一、Application的作用

1、保存应用程序的全局变量

2、作一些初始化操作

3、提供上下文

二、Application的类继承关系

这里Application继承自ContextWrapper, 而ContextWrapper又继承自Context,对于ContextWrapper而言,里面持有一个Context mBase,实际上是一个静态代理。如下

public class Application extends ContextWrapper implements ComponentCallbacks2 {
}

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * 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;
    }

    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }
}

三、Application的生命周期及初始化流程

生命周期

1、Constructor

2、attachBaseContext(Context context)

3、onCreate()

Application的初始化流程

在上一篇文章讲到应用进程的启动流程时,应用进程的启动会进入到ActivityThread#main()函数中,再来看看main函数是什么 样的

public static void main(String[] args) {
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

创建Looper之后,调用ActivityThread.attach方法,该方法内部就是对Application的创建及初始化操作。来看看attach方法是什么样的

private void attach(boolean system, long startSeq) {
            ...
        //获取AMS的binder对象
        final IActivityManager mgr = ActivityManager.getService();
            ...

        //通过binder对象调用AMS的attachApplication
        mgr.attachApplication(mAppThread, startSeq);
            ...
        
        //执行Application的onCreate方法
        mInitialApplication.onCreate();
    }

通过AMS的binder对象调用attachApplication最终会调用到AMS中的attachApplication函数,函数如下

@Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();

            //核心方法调用
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);

            Binder.restoreCallingIdentity(origId);
        }
    }
在attachApplication中通过核心方法调用到attachApplicationLocked函数,来看看attachApplicationLocked是什么样的,这个方法代码非常的多,这里我们只关心核心步骤,实际上只有一步thread.bindApplication(),
private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
    ...
    //这里的thread实际上是AMS持有的应用程序的binder句柄,这里是调用ActivityThread中的bindApplication函数
    thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
    ...
}

如上注释,调用ActivityThread中的bindApplication函数,这个函数参数特别多,在ActivityThread中把这些参数封装在AppBindData中

public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, boolean autofillCompatibilityEnabled) {
           
            //把上面参数封装在AppBindData中,发送到主线程的消息队列中
            AppBindData data = new AppBindData();
            ...
            sendMessage(H.BIND_APPLICATION, data);
        }

在ActivityThread中的H(接收上面sendMessage中的Handler)的handMessage()中收到BIND_APPLICATION后调用

handleBindApplication(data),这个方法代码也特别多,这里我们同样只关心核心主流程的东西
private void handleBindApplication(AppBindData data) {
    ...
    //这里的返回的是LoadedApk
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

    ...
    //实际上是LoadedApk中的makeApplication方法
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    
    ...
    mInstrumentation.callApplicationOnCreate(app);
    ...
}

这里makeApplication是调用LoadedApk中的方法,看看LoadeApk中是如何创建application中的

public Application makeApplication(boolean forceDefaultAppClass,
                                       Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
        ...
        //创建context
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        ...
        //创建Application,内部实际上通过ClassLoader去加载Application的className
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);

        mActivityThread.mAllApplications.add(app);
        
        return app;
    }

Instrumentation中newApplication实际上通过ClassLoader去加载传进来的Application className去生成Application对象的,对于不同的Android不同的版本,处理有些不一样,但是原理是一样的。

public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }

在Application中的attach()方法会调用到Application的attachBaseContext(),也就是我们应用Application所看到的attachBaseContext()。

到这里Application的基本启动流程就说完了。我们这里只关注核心流程,不关注其它细节,弄清查主流程的来龙去脉即可。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值