BroadcastReceiver几种常见监听
前言
Context也就是上下文对象,是Android较为常用的类,但是对于Context,很多人都停留在会用的阶段,这个系列会带大家从源码角度来分析Context,从而更加深入的理解它。
1.Context概述
Context意为上下文或者场景,是一个应用程序环境信息的接口。
在开发中我们经常会使用Context,它的使用场景总的来说分为两大类,它们分别是:
- 使用Context调用方法,比如:启动Activity、访问资源、调用系统级服务等。
- 调用方法时传入Context,比如:弹出Toast、创建Dialog等。
Activity、Service和Application都是间接的继承自Context的,因此,我们可以计算出一个应用程序进程中有多少个Context,这个数量等于Activity和Service的总个数加1,1指的是Application的数量。
Context是一个抽象类,它的内部定义了很多方法以及静态常量,它的具体实现类为ContextImpl。和Context相关联的类,除了ContextImpl还有ContextWrapper、ContextThemeWrapper和Activity等等,下面给出Context的关系图。
从图中我们可以看出,ContextImpl和ContextWrapper继承自Context,ContextWrapper内部包含有Context类型的mBase对象,mBase具体指向的是ContextImpl。ContextImpl提供了很多功能,但是外界需要使用并拓展ContextImpl的功能,因此设计上使用了装饰模式,ContextWrapper是装饰类,它对ContextImpl进行包装,ContextWrapper主要是起了方法传递作用,ContextWrapper中几乎所有的方法实现都是调用ContextImpl的相应方法来实现的。
ContextThemeWrapper、Service和Application都继承自ContextWrapper,这样他们都可以通过mBase来使用Context的方法,同时它们也是装饰类,在ContextWrapper的基础上又添加了不同的功能。
ContextThemeWrapper中包含和主题相关的方法(比如: getTheme方法),因此,需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service则继承ContextWrapper。
2.Application Context的创建过程
我们通过调用getApplicationContext来获取应用程序的全局的Application Context,那么Application Context是如何创建的呢?
当一个应用程序启动完成后,应用程序就会有一个全局的Application Context。那么我们就从应用程序启动过程开始着手。
在Android深入四大组件(一)应用程序启动过程(后篇)这篇文章的最后讲了ActivityThread启动Activity。ActivityThread作为应用程序进程的核心类,它会调用它的内部类ApplicationThread的scheduleLaunchActivity方法来启动Activity,如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends ApplicationThreadNative {
...
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
...
}
在ApplicationThread的scheduleLaunchActivity方法中向H类发送LAUNCH_ACTIVITY类型的消息,目的是将启动Activity的逻辑放在主线程中的消息队列中,这样启动Activity的逻辑会在主线程中执行。我们接着查看H类的handleMessage方法对LAUNCH_ACTIVITY类型的消息的处理。
frameworks/base/core/java/android/app/ActivityThread.java
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = ;
...
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);//
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
H继承自Handler ,是ActivityThread的内部类。在注释1处通过getPackageInfoNoCheck方法获得LoadedApk类型的对象,并将该对象赋值给ActivityClientRecord 的成员变量packageInfo,其中LoadedApk用来描述已加载的APK文件。在注释2处调用handleLaunchActivity方法,如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
Activity a = performLaunchActivity(r, customIntent);
...
}
我们接着查看performLaunchActivity方法:
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
}
...
return activity;
}
performLaunchActivity方法中有很多重要的逻辑,这里只保留了Application Context相关的逻辑,想要更多了解performLaunchActivity方法中的逻辑请查看Android深入四大组件(一)应用程序启动过程(后篇)这篇文章的第二小节。这里ActivityClientRecord 的成员变量packageInfo是LoadedApk类型的,我们接着来查看LoadedApk的makeApplication方法,如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {//
return mApplication;
}
...
try {
...
java.lang.ClassLoader cl = getClassLoader();
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);//
appContext.setOuterContext(app);//
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;//
...
return app;
}
注释1处如果mApplication不为null则返回mApplication,这里假设是第一次启动应用程序,因此mApplication为null。在注释2处通过ContextImpl的createAppContext方法来创建ContextImpl。注释3处的代码用来创建Application,在Instrumentation的newApplication方法中传入了ClassLoader类型的对象以及注释2处创建的ContextImpl 。在注释4处将Application赋值给ContextImpl的Context类型的成员变量mOuterContext。注释5处将Application赋值给LoadedApk的成员变量mApplication,在Application Context的获取过程中我们会再次用到mApplication。我们来查看注释3处的Application是如何创建的,Instrumentation的newApplication方法如下所示。
frameworks/base/core/java/android/app/Instrumentation.java
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();//
app.attach(context);
return app;
}
Instrumentation中有两个newApplication重载方法,最终会调用上面这个重载方法。注释1处通过反射来创建Application,并调用了Application的attach方法,并将ContextImpl传进去:
frameworks/base/core/java/android/app/Application.java
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
attach方法中调用了attachBaseContext方法,它的实现在Application的父类ContextWrapper中,代码如下所示。
frameworks/base/core/java/android/content/ContextWrapper.java
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
从上文我们得知,这个base指的是ContextImpl,将ContextImpl赋值给ContextWrapper的Context类型的成员变量mBase。Application Context的创建过程就讲到这里,最后给出Application Context创建过程的时序图。
绘图1_副本.png
3.Application Context的获取过程
当我们熟知了Application Context的创建过程,那么它的获取过程会非常好理解。我们通过调用getApplicationContext方法来获得Application Context,getApplicationContext方法的实现在ContextWrapper中,如下所示。
frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
从上文我们得知,mBase指的是ContextImpl,我们来查看 ContextImpl的getApplicationContext方法:
frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
如果LoadedApk不为null,则调用LoadedApk的getApplication方法,否则调用AvtivityThread的getApplication方法。由于应用程序这时已经启动,因此LoadedApk不会为null,则会调用LoadedApk的getApplication方法:
frameworks/base/core/java/android/app/LoadedApk.java
Application getApplication() {
return mApplication;
}
这里的mApplication我们应该很熟悉,它在上文LoadedApk的makeApplication方法的注释5处被赋值。这样我们通过getApplicationContext方法就获取到了Application Context。
BroadcastReceiver几种常见监听的更多相关文章
- android BroadcastReceiver ACTION_TIME_TICK 系统时间监听不到
android BroadcastReceiver ACTION_TIME_TICK 系统时间监听不到 今天做android上的消息推送,启动了一个独立service,然后在里面监听系统的ACTION ...
- 三种方式监听NGUI的事件方法
NGUI研究院之三种方式监听NGUI的事件方法(七) NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定 ...
- jQuery中四种事件监听的区别
原文链接:点我 我们知道jquery提供了四种事件监听方式,分别是bind.live.delegate.on,下面就分别对这四种事件监听方式分析. 已知有4个列表元素: 列表元素1 列表元素2 列表元 ...
- 【转】NGUI研究院之三种方式监听NGUI的事件方法(七)
NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,当按钮点击时就可以监听到,这种方法不太好很不 ...
- 两种js监听滚轮事件的方式
前段时间在写前端的时候,需要监听浏览器的滚轮事件 网上查了一下,找到两种监听滚轮事件的方法: 一.原生js通过window.onscroll监听 //window.onscroll = functio ...
- spring与activemq(三种消息监听方式)
1.3 消息监听器MessageListener 在Spring整合JMS的应用中我们在定义消息监听器的时候一共可以定义三种类型的消息监听器,分别是MessageListener.Sessio ...
- (转)NGUI研究院之三种方式监听NGUI的事件方法
NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,当按钮点击时就可以监听到,这种方法不太好很不 ...
- ALERT日志中常见监听相关报错之中的一个:ORA-609错误的排查
參考MOS文档有: Troubleshooting Guide ORA-609 : Opiodr aborting process unknown ospid (文档 ID 1121357.1) Al ...
- ALERT日志中常见监听相关报错之三:ORA-609 TNS-12537 and TNS-12547 or TNS-12170 TNS-12535错误的排查
1.11G中ALERT日志中有报错ORA-609 TNS-12537 and TNS-12547 or TNS-12170 12170, 'TNS-12535等问题的解决方法: Troublesho ...
随机推荐
- ABAP单元测试最佳实践
本文包含了我在开发项目中经历过的实用的ABAP单元测试指导方针.我把它们安排成为问答的风格,欢迎任何人添加更多的Q&A's,以完成这个列表. 在我的项目中,只使用传统的ABAP report. ...
- iOS:以前笔记,未整理版。太多了,先放着吧。。。。。。。
1. -(void)timetick { _d = 0; NSTimer *newtime =[NSTimer scheduledTimerWithTimeInterval:1 target:self ...
- ASP.NET Aries JSAPI 文档说明:AR.DataGrid
AR.DataGrid 文档 用法: <body> <table id="dg"></table> </body> </htm ...
- 【css3笔记】---- 渐变的秘密
<CSS揭秘>这本书非常不错,充满了干货和惊喜.以下主要是关于使用渐变做出来的一些效果的笔记.请用最新的现代浏览器观看. 首先要回顾下一个css语句: linear-gradient([ ...
- Unity3D和Egret3D的基情
Unity3D依靠多平台发布这个核心特点,目前如日中天,屌丝引擎之王绝无来者.Egret白鹭引擎,也着实在微信上刷了一屏又一屏.这二者似乎风马牛不相及,但是这个无处不搞基的年代,让一切皆有可能. U3 ...
- Centos6.5中安装和配置vsftp详细总结
一.vsftp安装篇 #查看是否安装:rpm -qa|grep vsftpd#卸载vsftpdrpm -e vsftpd-2.2.2-11.el6_3.1x86_64 --nodeps# 安装vsft ...
- Maven pom文件常用配置,转载
什么是POM Project Object Model,项目对象模型.通过xml格式保存的pom.xml文件.作用类似ant的build.xml文件,功能更强大.该文件用于管理:源代码.配置文件.开发 ...
- C#设计模式-策略者模式
状态模式是对某个对象状态的抽象,而本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方法的抽象,下面具体分享下我对策略模式的理解. 一. 策略者(Stragety)模式 在现实 ...
- Bootstrap3系列:导航
1. 标签页 .nav添加.nav-tabs设计标签页,.nav-tabs 依赖 .nav 基类. 1.1 示例代码 <ul class="nav nav-tabs"> ...
- Bootstrap WPF Style,Bootstrap风格的WPF样式
简介 GitHub地址:https://github.com/ptddqr/bootstrap-wpf-style 此样式基于bootstrap-3.3.0,样式文件里的源码行数都是指的这个版本.CS ...