发布于 

全局Application实例使用及分析

简单明了通过源码分析获取其Context对象实例

思考-分析-解决

通过Kaede Akatsuki的这篇文章了解到:

  • Application实例在App运行时,始终存在着。
  • ActivityThread匿名类中存在其实例的值

反射Context对象引用

1
2
3
4
5
6
7
8
Object activityThread = null;
try {
Method method = Class .forName("android.app.ActivityThread") .getMethod("currentActivityThread");
method.setAccessible(true);
activityThread = method.invoke(null);
} catch (final Exception e) {
Log.w(TAG, e);
}

其反射对应方法内容

1
2
3
4
@UnsupportedAppUsage
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}

emmm这里看了源码发现有两个可以直接反射出实例的方法

这里先给出源码

1
2
3
4
5
@UnsupportedAppUsage
public static Application currentApplication() {
ActivityThread am = currentActivityThread();
return am != null ? am.mInitialApplication : null;
}

注意到了没,这里已经将其currentActivityThread方法返回值转化为Application对象实例

那么问题看起来就简单多了

1
2
3
val method = Class.forName("android.app.ActivityThread")
.getDeclaredMethod("currentApplication")
context = method.invoke(null) as Application

至于为什么不使用try catch两点

  • 正常状态不会抛出异常 调试才会一直抛出
  • try catch 一旦使用 catch错误类型须写全 否则无法识别

比如这样

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
val method =Class.forName("android.app.ActivityThread")
.getDeclaredMethod("currentApplication")
context = method.invoke(null) as Application
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}

那第二种方法呢? 嗯。直接看源码

1
2
3
4
5
6
7
8
9
@UnsupportedAppUsage
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
mSystemContext = ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}

这个方法为什么看起来好眼熟 但是不能用哦

ContextImpl这个类是继承Context但是在Android sdk较低版本是未实现的类