Android中的Context主题似乎让很多人感到困惑。人们只知道在Android中做基本的事情经常需要Context。人们有时会感到恐慌,因为他们试图执行一些需要上下文的操作,他们不知道如何“获得”正确的上下文。我将尝试揭开Android中Context的神秘面纱。对该问题的完整处理超出了本文的范围,但我将尝试给出一般概述,以便您了解Context是什么以及如何使用它。要了解Context是什么,让我们来看看源代码:
什么是Context?
好吧,文档本身提供了一个相当简单的解释:Context类是“关于应用程序环境的全局信息的接口”。
Context类本身被声明为抽象类,其实现由Android OS提供。该文档进一步规定Context“...允许访问特定于应用程序的资源和类,以及对应用程序级操作的上调,例如启动活动,广播和接收意图等”。
你现在可以理解为什么这个名字是Context。这是因为就是这样。Context(如果您愿意)为活动,服务或任何其他组件提供链接或挂钩,从而将其链接到系统,从而允许访问全局应用程序环境。换句话说:上下文提供了组件问题的答案:“我到底与app有什么关系?我如何访问/与应用程序的其余部分进行通信?”如果这一切看起来有点令人困惑,请快速查看Context类公开的方法提供了一些关于其真实性质的进一步线索。
以下是这些方法的随机抽样:getAssets()
getResources()
getPackageManager()
getString()
getSharedPrefsFile()
所有这些方法有什么共同之处?它们都允许有权访问Context的任何人能够访问应用程序范围的资源。
换句话说,上下文将具有对它的引用的组件挂钩到应用程序环境的其余部分。例如,资产(例如项目中的'/ assets'文件夹)可在整个应用程序中使用,前提是活动,服务或其他任何知道如何访问这些资源的人。同样的事情getResources()允许做一些事情getResources().getColor()会把你挂钩到colors.xml资源(永远不要说aapt允许通过java代码访问资源,这是一个单独的问题)。
结果就是Context能够访问系统资源及其将组件挂钩到“更大的应用程序”中的内容。让我们看一下Context提供抽象Context类实现的类的子类。最明显的类是Activity类。Activity继承来自ContextThemeWrapper,继承自ContextWrapper,继承自Context自己。这些类对于在更深层次上理解事物是有用的,但是现在它足以知道它们ContextThemeWrapper并且ContextWrapper几乎就是它们听起来的样子。它们实现了抽象元素。Context类本身通过“包装”上下文(实际上下文)并将这些函数委托给该上下文。一个例子是有用的 - 在ContextWrapper类,抽象方法getAssets从Context类是这样实现的:@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
mBase只是由构造函数设置为特定上下文的字段。因此,上下文被包装并将ContextWrappergetAssets方法的实现委托给该上下文。让我们回过头来检查Activity最终继承的类,Context看看这一切是如何运作的。
您可能知道什么是活动,但要审查 - 它基本上是“用户可以做的一件事”。它负责提供一个窗口,用于放置用户与之交互的UI。熟悉其他API甚至非开发人员的开发人员可能会将其本身视为“屏幕”。这在技术上是不准确的,但对我们的目的而言并不重要。那么如何做Activity和Context交互以及它们的继承关系究竟发生了什么?
同样,查看具体示例也很有帮助。我们都知道如何发起活动。如果你有“上下文”,你正在启动Activity,你只需要调用startActivity(intent),Intent描述你从哪个上下文开始一个Activity和你想要开始的Activity。这是熟悉的startActivity(this, SomeOtherActivity.class)。
什么是this?this是你的Activity,因为Activity该类继承自Context。完整的独家新闻是这样的:当你调用时startActivity,最终Activity类会执行如下所示的事情:Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode);
因此,它利用了execStartActivity从Instrumentation类(实际上是从一个内部类Instrumentation叫ActivityResult)。
在这一点上,我们开始看到系统内部。
这是操作系统实际处理一切的地方。那么Instrumentation如何准确地启动Activity呢?那么,帕拉姆this在execStartActivity上述方法是你的活动,即环境,并且execStartActivity利用这一背景下的。
这是一个30,000概述:Instrumentation类跟踪它正在监视的活动列表,以便完成它的工作。此列表用于协调所有活动,并确保在管理活动流程时一切顺利进行。
有些操作我还没有完全了解哪个坐标线程和进程问题。最终,ActivityResult使用本机操作 - ActivityManagerNative.getDefault().startActivity()使用Context您在调用时传入的操作startActivity。您传入的上下文用于协助“意图解决”(如果需要)。意图解析是系统在未提供意图目标时确定目标的过程。(有关详细信息,请查看此处的指南)。
为了让Android执行此操作,它需要访问由其提供的信息Context。具体来说,系统需要访问一个ContentResolver所以它可以“确定意图数据的MIME类型”。关于如何startActivity利用上下文的这一点有点复杂,我自己并不完全理解内部。我的主要观点只是为了说明如何访问应用程序范围的资源以执行对应用程序至关重要的许多操作。Context提供对这些资源的访问权限。一个更简单的例子可能是Views。我们都知道你创建了什么通过扩展RelativeLayout或其他View类的自定义视图 ,您必须提供一个带有的构造函数Context作为一个论点。实例化自定义视图时,您将传递上下文。为什么?因为View需要能够访问主题,资源和其他View配置详细信息。查看配置实际上是一个很好的例子。每个Context都有各种参数(实现中的字段Context),这些参数由OS本身设置,例如显示的尺寸或密度。很容易理解为什么这些信息对于设置视图等非常重要。
最后一句话: 出于某种原因,Android的新手(甚至是不那么新的人)似乎完全忘记了Android的面向对象编程。出于某种原因,人们试图将他们的Android开发转变为预先设想的范例或学习行为。
Android拥有它自己的范例和某种模式,如果放弃你预先设想的概念并简单阅读文档和开发指南,它实际上是非常一致的。然而,我的真实观点是,虽然“获得正确的背景”有时候会很棘手,但人们会因为遇到需要上下文并认为自己没有上下文的情况而无理恐慌。Java是一种面向对象的语言,具有继承设计。
您只有“拥有”Activity内部的上下文,因为您的活动本身继承自Context。它没有什么神奇之处(除了操作系统自己设置各种参数和正确“配置”你的上下文)所做的所有事情。因此,将内存/性能问题放在一边(例如,当您不需要或以对内存产生负面影响的方式执行上下文时保持对上下文的引用等),Context就像任何其他对象一样,它可以传递给它就像任何POJO(Plain Old Java Object)一样。有时您可能需要做一些聪明的事情来检索该上下文,但是除了Object本身之外的任何其他常规Java类都可以以可访问上下文的方式编写; 简单地公开一个带有上下文的公共方法,然后根据需要在该类中使用它。