Android Context ContextWrapper ContextImpl Activity Service关系

简介: Android Context ContextWrapper ContextImpl Activity Service关系

初识Context



对于Android开发者来说,Activity应该是接触到最早的四大组件之一。Activity可以渲染layout生成控件,可以获取图片资源、文本资源、动画资源等等,还可以启动另一个Activity,启动一个后台的Service。每个Activity都有一个Context,通过这个Context我们几乎可以做任何我们想做的事情。比如通过context.getSystemService(name)我们可以获取到Android的内部服务,通过LayoutInflater.from(context)可以加载布局,通过context.getString(resId)可以获取资源。Context在我们的学习初期,它几乎是万能的。


再后来一些,我们知道了Service,Application内部也有一个Context。然后我们知道了Service是后台的服务,它与Activity的最大的区别就是没有界面。Application在一个应用程序中只有一个。


直到有一天我们有可能被问到Activity、Service、Application它们都是Context的子类,它们有什么区别吗?Dialog构造函数中的Context 可以传Application的Context吗?一开始我们是答不上来的。于是我们翻开源码开始探究Context的实现原理


Context源码解析



Context类图

Android Context类图.png

Context和Context子类的源码


1. Context源码


frameworks/base/core/java/android/content/Context.java

public abstract class Context {
    public abstract AssetManager getAssets();
    public abstract Resources getResources();
    public abstract SharedPreferences getSharedPreferences(File file, int mode);
    public abstract Context getApplicationContext();
    public abstract void startActivity(Intent intent);
    public abstract ComponentName startService(Intent service);
    public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter);
    public final String getString(@StringRes int resId) {
        return getResources().getString(resId);
    }
    public final CharSequence getText(@StringRes int resId) {
        return getResources().getText(resId);
    }
    public final Drawable getDrawable(@DrawableRes int id) {
        return getResources().getDrawable(id, getTheme());
    }
    ...省略其他方法
}

在Context.java中,我列举出了一些大家经常用到的方法,它们基本上都是抽象方法。看来真正实现了这些方法的Context并不是Context类本尊啊。我们沿着类图的右边继续阅读源码。


2. ContextWrapper源码


frameworks/base/core/java/android/content/ContextWrapper.java


public class ContextWrapper extends Context {
    Context mBase;
    public ContextWrapper(Context base) {
        mBase = base;
    }
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    public Context getBaseContext() {
        return mBase;
    }
    public abstract AssetManager getAssets(){
        return mBase.getAssets();
    }
    ...省略其他方法
}


在Context.java中,我列举出了一些大家经常用到的方法,它们基本上都是抽象方法。看来真正实现了这些方法的Context并不是Context类本尊啊。我们沿着类图的右边继续阅读源码。


2. ContextWrapper源码


frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;
    public ContextWrapper(Context base) {
        mBase = base;
    }
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    public Context getBaseContext() {
        return mBase;
    }
    public abstract AssetManager getAssets(){
        return mBase.getAssets();
    }
    ...省略其他方法
}


我这里选取getAssets()方法作为一个代表,其余的类似方法其实也是一样,篇幅有限故省略不表。对比下ContextWrapper和Context类。他们的区别有


ContextWrapper是Context的子类

ContextWarpper多了一个成员变量Context mBase

ContextWrapper多了一个构造函数和attachBaseContext(Context base),他们都是给mBase赋值

Context中定义的抽象方法getAssets()在ContextWrapper中被实现了


ContextWrapper中的方法比如getAssets()、getResource()都是通过调用mBase对象的相关方法来实现的。那么mBase到底是什么,是Context类的实例吗?不是!是Activity、Service、Application吗?不是(因为这些类中,也没有getAssets的具体实现)!那就只能是左边的ContextImpl了。接下来我们看看ContextImpl的源码,看看是否它就是ContextWrapper的mBase。


3. ContextImpl源码

frameworks/base/core/java/android/app/ContextImpl.java


class ContextImpl extends Context{
    final ActivityThread mMainThread;
    final LoadedApk mPackageInfo; 
    private final IBinder mActivityToken
    private final String mBasePackageName;
    private final String mOpPackageName;
    private final @NonNull ResourcesManager mResourcesManager;
    private final @NonNull Resources mResources;
    private Context mOuterContext;
    private int mThemeResource = 0;
    private Resources.Theme mTheme = null;
    private PackageManager mPackageManager;
    @Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }
    @Override
    public Resources getResources() {
        return mResources;
    }
    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }
        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }
        return null;
    }
     @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }
    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
        // generally not allowed, except if the caller specifies the task id the activity should
        // be launched in.
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }
}

首先我们来看下我们常用的一些方法getAssets()、getResource()、getPackageManager()、startActivity(Intent intent),它们在ContextImpl类中都有了具体的实现。可以片面的确定ContextWrapper的mBase指向的就是ContextImpl的实例对象!!!注意这里只是片面的推断后面还会有更科学、更有理有据、更严肃的推断。大家先记住这个结论就好了,暂时记作不严谨的结论吧。后面会用事实证明


接下来我们看下几个ContextImpl字段。


ActivityThread mMainThread这个顾名思义好像是Activity的线程啊?其实不是!从源码来看它并不继承于Thread


frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {
    private ContextImpl mSystemContext;
    static volatile IPackageManager sPackageManager;
    final ApplicationThread mAppThread = new ApplicationThread();
    final Looper mLooper = Looper.myLooper();
    final H mH = new H();
    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
    // List of new activities (via ActivityRecord.nextIdle) that should
    // be reported when next we idle.
    ActivityClientRecord mNewActivities = null;
    // Number of activities that are currently visible on-screen.
    int mNumVisibleActivities = 0;
    ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
    private int mLastSessionId;
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
    AppBindData mBoundApplication;
    Profiler mProfiler;
    int mCurDefaultDisplayDpi;
    boolean mDensityCompatMode;
    Configuration mConfiguration;
    Configuration mCompatConfiguration;
    Application mInitialApplication;
    final ArrayList<Application> mAllApplications
            = new ArrayList<Application>();
}
1. ContextImpl mSystemContext这个是系统应用才会有的。具体干嘛用的暂时还不知道
2. ApplicationThread mAppThread,mAppThread是用来和ActivityManagerService端的ApplicationThreadProxy通信的。他是Binder的子类。是IPC通信的服务端。当ActivityManagerService对Activity做了相应处理的时候,客户端程序需要通过mAppThread来做相应的处理。比如生成或控制Activity、Service、Application的生命周期
3. Looper mLooper是android应用程序的主looper
4. ArrayMap<IBinder, ActivityClientRecord> mActivities 当前应用程序所有的Activity在客户端的记录
5. int mNumVisibleActivities当前可见的Activity数量
6. ArrayMap<IBinder, Service> mServices = new ArrayMap<>()当前应用程序所有的Service在客户端的记录
7. H mH = new H(),H extends Handler mH就是一个Handler,mH是和主线程的Looper绑定的,换言之就是mH的handleMessage()是在主线程执行的。ApplicationThread的方法是在Binder线程池中执行的。在Binder线程中启动Activity需要用mH切换到主线程中执行。由于启动Activity不是本文的讲解范围,就不费过多笔墨了。
8. ActivityThread在一个应用程序中只有一个实例。但是如果应用程序开启了多进程模式,ActivityThread可能会有多份。比如Service指定android:process为:another。

LoadedApk mPackageInfo这个是用来记录Apk信息的。LoadedApk是在ActivityThread的handleBindApplication()方法中被创建


frameworks/base/core/java/android/app/ActivityThread.java

 private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
            boolean registerPackage) {
        final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
        synchronized (mResourcesManager) {
            WeakReference<LoadedApk> ref;
            if (differentUser) {
                // Caching not supported across users
                ref = null;
            } else if (includeCode) {
                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) Slog.v(TAG, (includeCode ? "Loading code package "
                        : "Loading resource-only package ") + aInfo.packageName
                        + " (in " + (mBoundApplication != null
                                ? mBoundApplication.processName : null)
                        + ")");
                packageInfo =
                    new LoadedApk(this, aInfo, compatInfo, baseLoader,
                            securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
                if (mSystemThread && "android".equals(aInfo.packageName)) {
                    packageInfo.installSystemApplicationInfo(aInfo,
                            getSystemContext().mPackageInfo.getClassLoader());
                }
                if (differentUser) {
                    // Caching not supported across users
                } else if (includeCode) {
                    mPackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                }
            }
            return packageInfo;
        }
    }

从源码中我们可以知道,LoadedApk是保存在WeakReference中。如果获取到为null就重新生成LoadedApk

3. IBinder mActivityToken是WindowManager的远程代理对象


4. Activity、Service、Appplication

前面我们讲了ContextWrapper的Context mBase指向的是具体的ContextImpl对象。而Activity、Service、Application也都是ContextWrapper的直接子类或间接子类。mBase是通过attachBaseContext(Context context)来赋值的。


通读Activity、Service、Application的源码。发现attachBaseContext方法会在attach方法中被调用


1. Activity源码

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
        ...省略其他
        final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);//1
        mFragments.attachHost(null /*parent*/);
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();
        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }
}

注释1处说明会通过attachBaseContext(context)把真正的context赋值给mBase。那么顺着调用Activity的attach方法。发现调用者为ActivityThread的handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)


frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...省略其他
     Activity a = performLaunchActivity(r, customIntent);
    ...省略其他
}

接着看ActivityThread的performLaunchActivity(r,customIntent)方法,由于方法比较长我会在代码里写注释讲解


frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
        Activity activity = null;
        try {
            //获取Android程序的ClassLoader mark0
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //通过反射创建activity.此时Context mBase还没有被赋值
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
        try {
            //生成程序全局的Application对象,如果存在直接返回,如果不存在则生成,
            //mark1 接下来讲解Application的时候会讲到
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            if (activity != null) {
                //创建给Activity使用的ContextImpl 
                //mark2
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                //通过activity的attach方法把生成的appContext赋值给Activity
                //mark3
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;
            //把ActivityClientRecord存储到ArrayMap中。在handleResumeActivity中通过token获取mActivities中的ActivityClientRecord
            //mark4
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }
        return activity;
    }

以上代码与本文讲解Context相关总结如下


1. mark0 通过反射生成Activity

2. mark1 通过反射生成Application

3. mark2 调用ActivityThread的createBaseContextForActivity生成ContextImpl

4. mark3 并通过Activity.attach赋值给Activity的mBase。这里就完美回答了上面关于ContextImpl源码处的那个不严谨的结论

5. mark4 把ActivityClientRecord记录到ArrayMap中


mark2处 createBaseContextForActivity源码如下


frameworks/base/core/java/android/app/ActivityThread.java

 private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        int displayId = Display.DEFAULT_DISPLAY;
        try {
            displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);//1
        appContext.setOuterContext(activity);//2
        Context baseContext = appContext;
        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
        // For debugging purposes, if the activity's package name contains the value of
        // the "debug.use-second-display" system property as a substring, then show
        // its content on a secondary display if there is one.
        String pkgName = SystemProperties.get("debug.second-display.pkg");
        if (pkgName != null && !pkgName.isEmpty()
                && r.packageInfo.mPackageName.contains(pkgName)) {
            for (int id : dm.getDisplayIds()) {
                if (id != Display.DEFAULT_DISPLAY) {
                    Display display =
                            dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
                    baseContext = appContext.createDisplayContext(display);
                    break;
                }
            }
        }
        return baseContext;
    }

//1 处通过ContextImpl createActivityContext生成ContextImpl。对应的还有两个类似的方法ActivityThread mainThread和createAppContext(ActivityThread mainThread, LoadedApk packageInfo)。后面我把它们放在一起对比。更容易了解到差别

//2 处给ContextImpl设置了outerContext。这里outerContext就是Activity。归纳总结就是Activity的mBase的outerContext就是Activity本身。Service的mBase的outerContext就是Service本身。Application的mBase的outerContext就是Application本身。是不是有点拗口。


2. Application 创建源码


Application创建地方有两处


1.第一处在前面mark1处,通过makeApplication创建Application

    //r.packageInfo为 frameworks/base/core/java/android/app/LoadedApk
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);

frameworks/base/core/java/android/app/LoadedApk

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
        Application app = null;
        //如果AndroidManifest中没有声明Application用默认的
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }
        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            //mark1 创建Applicaiton的ContextImpl对象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //mark2 通过反射生成Applicaiton对象并attach(appContext)
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //mark3 设置outerContext
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }
        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
                .getAssignedPackageIdentifiers();
        final int N = packageIdentifiers.size();
        for (int i = 0; i < N; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }
            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        return app;
    }

生成Applicaiton总结如下


1.mark1 创建Applicaiton的ContextImpl对象

2.mark2 通过反射生成Applicaiton对象并attach(appContext)


frameworks/base/core/java/android/app/Instrumentation

 static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }
2.第二处在ActivityThread的handleBindApplication()中,这里才是Application第一次被创建的地方


private void handleBindApplication(AppBindData data) {
    ...省略其他代码
    //和前面讲解的一样
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    ...省略其他代码
}
  1. mark3 设置outerContext


Application源码如下

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
}

3. Service 创建源码


  1. Service部分源码如下
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }
}
  1. ActivityThread的handleCreateService()会创建Service

frameworks/base/core/java/android/app/ActivityThread.java

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        //mark1 反射生成Service对象
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            //mark2 生成ContextImpl 和Application一样
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            //确保Application已经生成
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //mark3 调用service的attach方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

Service创建总结如下


  1. 反射生成Service对象
  2. 生成ContextImpl 和Application一样
  3. 调用service的attach方法

4. ContextImpl的createActivityContext和createAppContext区别

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}
//    performLaunchActivity
static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
                null, overrideConfiguration, displayId);
}

对比以上代码发现,他们的方法参数的差别在IBinder activityToken。而activityToken其实是与界面相关的。如果用Application或者Service创建Dialog是会报错的。原因就是没有activityToken


4. Dialog报错模拟

public class TestDialogActivity extends Activity{
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        new Dialog(getApplicationContext()).show();//要报错
        new Dialog(this).show();//不报错
    }
}
相关文章
|
3月前
|
Android开发
Android面试题之Activity的启动模式和flag
Android Activity的四种启动模式:standard(默认,每次启动创建新实例),singleTop(栈顶复用,不走onCreate,调用onNewIntent),singleTask(栈内唯一,清除上方Activity)和singleInstance(单独栈内唯一)。启动模式在AndroidManifest.xml中配置,Intent Flags如FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_SINGLE_TOP可实现类似功能。了解这些对于处理Activity栈管理至关重要。
43 0
|
9天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
25 4
|
2月前
|
XML Android开发 数据格式
android中两个Activity同时设定了intent-filter的category为android.intent.category.LAUNCHER,会发生什么情况?
本文通过案例分析了在Android中当两个Activity都设置了`android.intent.category.LAUNCHER`类别时,会导致它们同时在应用启动器的"所有应用"页面显示为不同的启动入口。
32 2
android中两个Activity同时设定了intent-filter的category为android.intent.category.LAUNCHER,会发生什么情况?
|
9天前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
16 0
|
2月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
2月前
|
开发工具 Android开发
解决Manifest merger failed : android:exported needs to be explicitly specified for <activity>
解决Manifest merger failed : android:exported needs to be explicitly specified for <activity>
42 1
|
3月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
60 12
|
4月前
|
Android开发 开发者
Android UI设计中,Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等,定义在`styles.xml`。
【6月更文挑战第26天】Android UI设计中,Theme定义了Activity的视觉风格,包括颜色、字体、窗口样式等,定义在`styles.xml`。要更改主题,首先在该文件中创建新主题,如`MyAppTheme`,覆盖所需属性。然后,在`AndroidManifest.xml`中应用主题至应用或特定Activity。运行时切换主题可通过重新设置并重启Activity实现,或使用`setTheme`和`recreate()`方法。这允许开发者定制界面并与品牌指南匹配,或提供多主题选项。
54 6
|
4月前
|
Android开发 UED 开发者
Android Activity启动模式详解
Android Activity启动模式详解
139 0
|
4月前
|
Android开发 UED
Android Activity的生命周期详解
Android Activity的生命周期详解
下一篇
无影云桌面