旅游网站建设课程设计,wordpress建立网站吗,昆明好seo怎么做,古腾堡布局的网站什么是Context
回想一下最初学习Android开发的时候#xff0c;第一用到context是什么时候#xff1f;如果你跟我一样是通过郭霖的《第一行代码》来入门android#xff0c;那么一般是Toast。Toast的常规用法是#xff1a;
Toast.makeText(this, 我是toast, To…什么是Context
回想一下最初学习Android开发的时候第一用到context是什么时候如果你跟我一样是通过郭霖的《第一行代码》来入门android那么一般是Toast。Toast的常规用法是
Toast.makeText(this, 我是toast, Toast.LENGTH_SHORT).show()当初也不知道什么是Context只知道他需要一个context类型把activity对象传进去即可。从此context贯穿在我开发过程的方方面面但我始终不知道这个context到底有什么用为什么要这个对象我们首先来看官方对于Context类的注释
/*** Interface to global information about an application environment. This is* an abstract class whose implementation is provided by* the Android system. It* allows access to application-specific resources and classes, as well as* up-calls for application-level operations such as launching activities,* broadcasting and receiving intents, etc.*/
public abstract class Context {...}
关于应用程序环境的全局信息的接口。 这是一个抽象类它的实现是由Android系统提供。 它允许访问特定应用的资源和类以及向上调用应用程序级的操作如启动活动广播和接收Intent等。
可以看到Context最重要的作用就是获取全局消息、访问系统资源、调用应用程序级的操作。可能对于这些作用没什么印象想一下如果没有context我们如何做到以下操作
弹出一个toast启动一个activity获取程序布局文件、drawable文件等访问数据库
这些平时看似简单的操作一旦失去了context将无法执行。这些行为都有一个共同点需要与系统交汇。四大组件为什么配为组件而我们的写的就只能叫做一个普通的Java类正是因为context的这些功能让四大组件有了不一样的能力。简单来说context是应用程序和系统之间的桥梁应用程序访问系统各种资源的接口。 我们一般使用context最多的是两种情景直接调用context的方法和调用接口时需要context参数。这些行为都意味着我们需要访问系统相关的资源。
那context是从哪里来的AMSAMS是系统级进程拥有访问系统级操作的权利应用程序的启动受AMS的调控在程序启动的过程中AMS会把一个“凭证”通过跨进程通信给到我们的应用程序我们的程序会把这个“凭证”封装成context并提供一系列的接口这样我们的程序也就可以很方便地访问系统资源了。这样的好处是系统可以对应用程序级的操作进行调控限制各种情景下的权限同时也可以防止恶意攻击。 如Application类的context和Activity的context权利是不一样的生命周期也不一样。对于想要操作系统攻击用户的程序也进行了阻止没有获得允许的Java类没有任何权利而Activity开放给用户也只有部分有限的权利。而我们开发者获取context的路径也只有从activity、application等组件获取。
因而什么是ContextContext是应用程序与系统之间沟通的桥梁是应用程序访问系统资源的接口同时也是系统给应用程序的一张“权限凭证”。有了context一个Java类才可以被称之为组件。
Context家族
上一部分我们了解什么是context以及context的重要性这一部分就来了解一下context在源码中的子类继承情况。先看一个图 最顶层是Context抽象类他定义了一系列与系统交汇的接口。ContextWrapper继承自Context但是并没有真正实现Context中的接口而是把接口的实现都托管给ContextImplContextImpl是Context接口的真正实现者从AMS拿来的“凭证”也是封装到了ContextImpl中然后赋值给ContextWrapper这里运用到了一种模式装饰者模式。Application和Service都继承自ContextWrapper那么他们也就拥有Context的接口方法且本身即是context方便开发者的使用。Activity比较特殊因为它是有界面的所以他需要一个主题ThemeContextThemeWrapper在ContextWrapper的基础上增加与主题相关的操作。
这样的设计有这样的优点
Activity等可以更加方便地使用context可以把自身当成context来使用遇到需要context的接口直接把自身传进去即可。运用装饰者模式向外屏蔽ContextImpl的内部逻辑同时当需要更改ContextImpl的逻辑实现ContextWrapper的逻辑几乎不需要更改。更方便地扩展不同情景下的逻辑。如service和activity情景不同需要的接口方法也不同但是与系统交互的接口是相同的使用装饰者模式可以拓展出很多的功能同时只需要把ContextImpl对象赋值进去即可。
context的分类
前面讲到Context的家族体系时了解到他的最终实现类有Application、Activity、ServiceContextImpl被前三者持有是Context接口的真正实现。那么这里讨论一下这三者有什么不同和使用时需要注意的问题。
Application
Application是全局Context整个应用程序只有一个他可以访问到应用程序的包信息等资源信息。获取Application的方法一般有两个
context.getApplicationContext()
activity.getApplication()
通过context和activity都可以获取到Application那这两个方法有什么区别没有区别。但为什么要提供两个一样作用的方法getApplication()方法更加直观但是只能在activity中调用。getApplicationContext()适用范围更广任意一个context对象皆可以调用此方法。 Application类的Context的特点是生命周期长在整个应用程序运行的期间他都会存在。同时我们可以自定义Application并在里面做一些全局的初始化操作或者写一个静态的context供给全局获取不需要在方法中传入context。如
class MyApplication : Application(){// 全局contextcompanion object{lateinit var context: Context}override fun onCreate() {super.onCreate()// 做全局初始化操作RetrofitManager.init(this)context this}
}这样我们就可以在应用启动的时候对一些组件进行初始化同时可以通过MyApplication.context来获取Application对象。
但是请不要把Application当成工具类使用。由于Application获取的便利性有开发者会在Application中编写一些工具方法全局获取使用这样是不行的。自定义Application的目的是在程序启动的时候做全局初始化工作而不能拿来取代工具类这严重违背谷歌设计Application的原则也违背Java代码规范的单一职责原则。 四大组件
Activity继承自ContextThemeWrapper是一个拥有主题的context对象。Activity常用于与UI有关的操作如添加window等。常规使用可以直接用activity.this。
Service继承自ContextWrapper也可以和Activity一样直接使用service.this来使用context。和activity不同的是Service没有界面所以也不需要主题。
ContentProvider使用的是Application的contextBroadcast使用的是activity的context这两点在后面会进行源码分析。
BaseContext
嗯baseContext是什么把这个拿出来单独讲细心的读者可能会发现activity中有一个方法getBaseContext。这个是ContextWrapper中的mBase对象也就是ContextImpl也是context接口的真正逻辑实现。
context的使用问题
使用context最重要的问题之一是注意内存泄露。不同的context的生命周期不同Application是在应用存在的期间会一直存在而Activity是会随着界面的销毁而销毁如果当我们的代码长时间持有了activity的context如静态引用或者单例类那么会导致activity无法被释放。如下面的代码
object MyClass {lateinit var mContext : Contextfun showToast(context : Context){mContext context}
}
单例类在应用持续的时间都会一直存在这样context也就会被一直被持有activity无法被回收导致内存泄露。
那我们就都换成Application不就可以了如下
object MyClass {lateinit var mContext : Contextfun showToast(context : Context){mContext context.applicationContext}
}答案是不可以。什么时候可以使用Application不涉及UI以及启动Activity操作Activity的context是拥有主题属性的如果使用Application来操作UI那么会丢失自定义的主题采用系统默认的主题。同时有些UI操作只有Activity可以执行如弹出dialog这涉及到window的token问题我在这篇文章token验证进行了详细的解答有兴趣的读者可以去阅读一下。这也是官方对于context不同权限的设计没有界面的context就不应该有操作界面的权利。使用Application启动的Activity必须指定task以及标记为singleTask因为Application是没有任务栈的需要重新开一个新的任务栈。因此我们需要根据不同context的不同职责来执行不同的任务。 总结
文章讲解了什么是context、context家族、已经不同的context实现类。 通过本文可以了解什么是context以及与context相关的类。那么接下来深入讲context源码相关内容.