Android上下文Context的使用说明书

下图是sdk基于26时的源码 image.png

2.创建dialog

使用application的context创建Dialog dialog = new Dialog(getApplicationContext()); 会报这样的错误

image.png 这又是为什么呢? 首先看一下Activity的attach()方法:

//activity

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, IBinder assistToken) {
attachBaseContext(context);

//创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);

//设置windowMananger 其中第二个参数为token
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

}

activity被创建后,会创建PhoneWindow和并设置windowManager绑定token。 这里的 IBinder 对象 mToken 很重要。它是一个 Binder 对象,可以在 app 进程,system_server 进程之间进行传递。和我们通常所说的 Token 一样,这里也可以把它看做是一种特殊的令牌,用来标识 Window ,在对 Window 进行视图操作的时候就可以做一些校验工作。

所以,Activity 对应的 Window/WMS 都是持有这个 mToken 的。结合之前 Application 创建 Dialog 的报错信息,我们可以大胆猜测 Application Context 创建 Dialog 的过程中,并没有实例化类似的 token。

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {

//获取context中的windowManager
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//创建window 并设置windowmanager
final Window w = new PhoneWindow(mContext);
w.setWindowManager(mWindowManager, null, null);
}

再来看看dialog的构造函数,从传入的context中拿到windowManager并创建新的window。我们知道dialog本质上也是一个window,显示的时候也是要通过WindowManager的addView()方式显示的。 看一下dialog的show()方法

//dialog

public void show() {
//通过addView方法–>windowManagerImpl的addView–>windowManagerGlobal的addView–>viewRootImpl的setView…
mWindowManager.addView(mDecor, l);

sendShowMessage();
}

如果传入的 Context 是 Activity,返回的是在 Activity.attach() 方法中创建的 mWindowManager 对象,这个时候 mToken 也已经绑定。

如果传入的 Context 是 Application,最终调用的是父类 ContextImpl 的方法。并没有绑定token

所以,Android 不允许 Activity 以外的 Context 来创建和显示普通的 Dialog (Toast这样的除外)。

3.生命周期导致的内存泄漏

在项目过程中,我们存在很多工具类,这些工具类不限于网络请求及一些工具方法,这些工具方法大多数是需要访问资源的,这时就需要Context的参与

public class SingleInstanceTest {

private SingleInstanceTest(final Context context) {
this.mContext = context;
}

private Context mContext;

public static volatile SingleInstanceTest singleInstanceTest;

public static SingleInstanceTest getInstance() {
if (singleInstanceTest == null) {
synchronized (SingleInstanceTest.class) {
if (singleInstanceTest == null) {
singleInstanceTest = new SingleInstanceTest(context);
}
}
}
return singleInstanceTest;
}
}

一个简单的单例模式,内部持有一个context的引用,这么写是没有问题的,问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this;这样问题就来了,我们的这个类中的singleInstanceTest是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说,我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,所以造成了内存泄漏。

如何解决呢?
public static SingleInstanceTest getInstance() {
if (singleInstanceTest == null) {
synchronized (SingleInstanceTest.class) {
if (singleInstanceTest == null) {
//使用ApplicationContext 因为ApplicationContext的生命周期跟app的周期一样长
singleInstanceTest = new SingleInstanceTest(context.getApplicationContext());
}
}
}
return singleInstanceTest;
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

尾声

如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

架构篇

《Jetpack全家桶打造全新Google标准架构模式》

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

(img-CQjpou6p-1713221840668)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 16
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值