Android 动态广播注册流程
1. 动态广播注册的流程
先看一下大致文件和流程如下(activity中动态注册广播):

2. 新建一个动态广播接收者
广播好久之前就准备写了,最近有时间就先把广播这部分写完
这篇文章就先将动态广播注册的流程
先看一下,在一个activity中注册一个亮屏的动态广播
//新建一个BroadcastReceiver,用于接收广播
public BroadcastReceiver mDynamicReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//onReceive是广播处理的时候的接收方法
Log.e("yunhen", "MyReceiver dynamic intent = " + intent.getAction());
}
};
//在需要注册广播的时候调用,写下类似下面的代码
//新建一个IntentFilter,意图过滤器
IntentFilter filter = new IntentFilter();
//增加亮屏的行为action
filter.addAction(Intent.ACTION_SCREEN_ON);
//注册广播,广播接受者是mDynamicReceiver,意图过滤器是filter
mContext.registerReceiver(mDynamicReceiver, filter);
3. App部分的registerReceiver
- activity中的registerReceiver,其调用的是ContextWrapper的registerReceiver
//ContextWrapper.java
public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
1.1) 至于mBase就是ContextImpl,这个又是在哪里设置的呢?
一个是在构造函数里面设置,一个是调用attachBaseContext设置,
如果是activity的mBase则是调用attachBaseContext设置
//ContextWrapper.java
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
1.2) 在ActivityThread.java的performLaunchActivity(启动应用时发出的LaunchActivityItem会执行activity生命周期的内容)
会新建new ContextImpl,并进行mBase赋值
//新建new ContextImpl流程
ActivityThread.java: performLaunchActivity->createBaseContextForActivity
ContextImpl.java: ->createActivityContext->new ContextImpl
得到ContextImpl之后通过activity.attach进行mBase下一步赋值
//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//...
//创建ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
//...
//将ContextImpl的mOuterContext设置成activity
appContext.setOuterContext(activity);
//将appContext赋值给Activity(Activity是ContextWrapper的子类)的mBase对象,
//在这里上面2个(mBase/mOuterContext)是一样的
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,
r.assistToken, r.shareableActivityToken);
//...
}
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
//此处在ActivityThread将this传入ContextImpl的mMainThread
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
//...
return appContext;
}
//ContextImpl.java
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
String[] splitDirs = packageInfo.getSplitResDirs();
//这里是LoadedApk的getClassLoader
ClassLoader classLoader = packageInfo.getClassLoader();
if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
try {
classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
} catch (NameNotFoundException e) {
// Nothing above us can handle a NameNotFoundException, better crash.
throw new RuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
final String attributionTag;
if (activityInfo.attributionTags != null && activityInfo.attributionTags.length > 0) {
attributionTag = activityInfo.attributionTags[0];
} else {
attributionTag = null;
}
//新建new ContextImpl,注意传入参数mainThread、classLoader等,还有createActivityContext函数的一些resources初始化
//传入的UserHandle user是null
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
null);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
context.mIsConfigurationBasedContext = true;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final ResourcesManager resourcesManager = ResourcesManager.getInstance();
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
context.setResources(resourcesManager.createBaseTokenResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
packageInfo.getOverlayPaths(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
classLoader,
packageInfo.getApplication() == null ? null
: packageInfo.

最低0.47元/天 解锁文章
5839





