Android 源码分析之xml和资源的加载

245 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

初始化activity的窗口

在ActivityThread中的performLaunchActivity方法来启动activity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ....
    //创建activity
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        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 app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            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;
            }
            appContext.setOuterContext(activity);
            //绑定
            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, r.configCallback);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            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.setState(ON_CREATE);
        mActivities.put(r.token, r);
    }
    ...
    return activity;
}

进入activity的attach方法

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, ActivityConfigCallback activityConfigCallback) {
    attachBaseContext(context);
    mFragments.attachHost(null /*parent*/);
    //会创建一个phoneWindow对象
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    //给mWindow初始化
    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);
    }
   ...
}

进入activity的setContentView方法

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

进入PhoneWindow中的setContentView方法

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
    ....
}

继续进入installDecor方法

private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
       //生成DecorView
        mDecor = generateDecor(-1);
        ...
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        //将mDecor作为根传递到generateLayout方法中
        mContentParent = generateLayout(mDecor);
       ...
    }
}

进入generateDecor方法,这个方法其实是生成一个DecorView对象,DecorView其实就是一个FrameLayout

protected DecorView generateDecor(int featureId) {
    ....
    return new DecorView(context, featureId, this, getAttributes());
}

进入generateLayout方法,然后找到系统资源文件中布局的ID,并生成根视图返回

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

到此activity的窗口已经加载好了,而且窗口添加了一个默认的布局FrameLayout,这些工作都是系统做的

加载自定义的布局文件setContentView

继续回到PhoneWindow类中的setContentView方法

mLayoutInflater.inflate(layoutResID, mContentParent);

layoutResID就是我们写的xml布局文件的id 进入LayoutInflater类的inflate方法

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        ```
        final View temp = createViewFromTag(root, name, inflaterContext, attrs);

        ViewGroup.LayoutParams params = null;

        if (root != null) {
            params = root.generateLayoutParams(attrs);
            if (!attachToRoot) {
                temp.setLayoutParams(params);
            }
        }
         ....
        return result;
    }
}

attachToRoot的作用,加载布局文件方式,如果是true代表动态加载,如果为false则将我们自己的根布局的参数添加到DecorView中去

进入createViewFromTag方法中

View view;
if (mFactory2 != null) {
    view = mFactory2.onCreateView(parent, name, context, attrs);
} else if (mFactory != null) {
    view = mFactory.onCreateView(name, context, attrs);
} else {
    view = null;
}
if (view == null && mPrivateFactory != null) {
    view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view == null) {
    final Object lastContext = mConstructorArgs[0];
    mConstructorArgs[0] = context;
    try {
        if (-1 == name.indexOf('.')) {
            view = onCreateView(parent, name, attrs);
        } else {
            view = createView(name, null, attrs);
        }
    } finally {
        mConstructorArgs[0] = lastContext;
    }
}

创建View的两种方式

  • Factory方式
  • infalter的createView(反射)
 public final View createView(@NonNull Context viewContext, @NonNull String name,
                                  @Nullable String prefix, @Nullable AttributeSet attrs)
                                  throws ClassNotFoundException, InflateException {
                              Objects.requireNonNull(viewContext);
                              Objects.requireNonNull(name);
                              Constructor<? extends View> constructor = sConstructorMap.get(name);
                              if (constructor != null && !verifyClassLoader(constructor)) {
                                  constructor = null;
                                  sConstructorMap.remove(name);
                              }
                              Class<? extends View> clazz = null;
                              try {
                                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
                      
                                  if (constructor == null) {
                                      clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
                                              mContext.getClassLoader()).asSubclass(View.class);
                      
                                      if (mFilter != null && clazz != null) {
                                          boolean allowed = mFilter.onLoadClass(clazz);
                                          if (!allowed) {
                                              failNotAllowed(name, prefix, viewContext, attrs);
                                          }
                                      }
                                      constructor = clazz.getConstructor(mConstructorSignature);//此处可以说明所有的自定义都会调用两个参数的构造函数
                                      constructor.setAccessible(true);
                                      sConstructorMap.put(name, constructor);
                                  } else {
                                      if (mFilter != null) {
                                          Boolean allowedState = mFilterMap.get(name);
                                          if (allowedState == null) {
                                              clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
                                                      mContext.getClassLoader()).asSubclass(View.class);
                      
                                              boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
                                              mFilterMap.put(name, allowed);
                                              if (!allowed) {
                                                  failNotAllowed(name, prefix, viewContext, attrs);
                                              }
                                          } else if (allowedState.equals(Boolean.FALSE)) {
                                              failNotAllowed(name, prefix, viewContext, attrs);
                                          }
                                      }
                                  }
                      
                                  Object lastContext = mConstructorArgs[0];
                                  mConstructorArgs[0] = viewContext;
                                  Object[] args = mConstructorArgs;
                                  args[1] = attrs;
                      
                                  try {
                                        //此处就创建好了我们自己定义的layoutView
                                      final View view = constructor.newInstance(args);
                                      if (view instanceof ViewStub) {
                                          final ViewStub viewStub = (ViewStub) view;
                                          viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
                                      }
                                      return view;
                                  } finally {
                                      mConstructorArgs[0] = lastContext;
                                  }
                              } finally {
                                  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                              }
                          }

View的创建是通过Factory工程模式来进行创建的,而Factory是给我们定义的一个接口,由此可见我们也可以来通过自定义这个Factory的方式来实现工厂的onCreatView()方法,方法中抄袭系统的createView()的实现来完成视图View的创建

通过createView我们可以发现,自定义的view是通过反射来进行加载的,最后将通过反射创建出一个view的实例并返回回去

加载资源文件

加载资源在activityThread中的handleBindApplication开始

创建一个仪表类
mInstrumentation = new Instrumentation();
创建一个application
app = data.info.makeApplication(data.restrictedBackupMode, null);

进入LoadedApk的makeApplication方法,发现会创建一个上下文

ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

进入createAppContext方法中

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
            null);
            //设置资源信息
    context.setResources(packageInfo.getResources());
    return context;
}

最后进入getOrCreateResources方法

private @Nullable Resources getOrCreateResources(@Nullable IBinder activityToken,
        @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
        ....
        final Resources resources;
        if (activityToken != null) {
            resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
                    resourcesImpl, key.mCompatInfo);
        } else {
            resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
        }
        ....
}

进入createResourcesImpl

private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
    final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
    daj.setCompatibilityInfo(key.mCompatInfo);
    final AssetManager assets = createAssetManager(key);
    if (assets == null) {
        return null;
    }
    final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
    final Configuration config = generateConfig(key, dm);
    final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
    return impl;
}

进入createAssetManager()方法,创建好了AssetManager的对象后返回该对象,用于生成ResourcesImpl 构建对象,这样就可以得到我们apk包中的资源了

protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
        final AssetManager.Builder builder = new AssetManager.Builder();
        if (key.mResDir != null) {
            try {
                builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/,
                        false /*overlay*/));
            } catch (IOException e) {
                Log.e(TAG, "failed to add asset path " + key.mResDir);
                return null;
            }
        }
        if (key.mSplitResDirs != null) {
            for (final String splitResDir : key.mSplitResDirs) {
                try {
                    builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/,
                            false /*overlay*/));
                } catch (IOException e) {
                    Log.e(TAG, "failed to add split asset path " + splitResDir);
                    return null;
                }
            }
        }
        if (key.mLibDirs != null) {
            for (final String libDir : key.mLibDirs) {
                if (libDir.endsWith(".apk")) {
                    try {
                        builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/,
                                false /*overlay*/));
                    } catch (IOException e) {
                        // continue.
                    }
                }
            }
        }

        if (key.mOverlayDirs != null) {
            for (final String idmapPath : key.mOverlayDirs) {
                try {
                    builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/,
                            true /*overlay*/));
                } catch (IOException e) {
                    // continue.
                }
            }
        }
        if (key.mLoaders != null) {
            for (final ResourcesLoader loader : key.mLoaders) {
                builder.addLoader(loader);
            }
        }
        return builder.build();
    }

到目前为止,我们已经找到了ResoucesImpl的实现,完成了上面的工作后,就会回调到我们自己app的application的OnCreate()方法中了

mInstrumentation.callApplicationOnCreate(app);