什么's不同的方法来获得一个Android上下文?

在不同的Android代码中,我看到:

 public class MyActivity extends Activity {
public void method() {
mContext = this;    // since Activity extends Context
mContext = getApplicationContext();
mContext = getBaseContext();
}
}

然而,我找不到任何像样的解释,说明哪种方法更可取,以及在什么情况下应该使用哪种方法。

如果您选择了错误的选项,将非常感谢您提供有关该选项的文档指针,以及关于可能出现故障的指导。

94321 次浏览

我同意,当涉及到Android中的上下文时,文档很少,但你可以从各种来源拼凑一些事实。

Android开发者官方博客谷歌上的这篇博文主要是为了帮助解决内存泄漏,但也提供了一些关于上下文的好信息:

在一个常规的Android应用程序中,你 通常有两种语境, 活动和应用程序。

进一步阅读这篇文章会告诉你两者之间的区别,以及什么时候你可能想考虑使用应用程序Context (Activity.getApplicationContext())而不是使用活动上下文this)。基本上,应用程序上下文是与应用程序相关联的,并且在应用程序的整个生命周期中始终是相同的,其中活动上下文是与活动相关联的,并且可能会在屏幕方向变化等过程中被破坏多次。

我找不到任何关于何时使用getBaseContext()的东西,除了Dianne Hackborn的一篇帖子,她是谷歌的工程师之一,致力于Android SDK:

不要使用getBaseContext(),只需使用

.

.

这是来自android开发者新闻组上的一篇文章,你可能想要考虑在那里问你的问题,因为少数人在Android上工作,实际监控新闻组并回答问题。

因此,总的来说,尽可能使用全局应用程序上下文似乎更可取。

首先,我同意我们应该尽可能使用appcontext。然后是"this" in activity。我从来不需要基本的上下文。

在我的测试中,大多数情况下它们是可以互换的。在大多数情况下,您想要获得上下文的原因是访问文件、首选项、数据库等。这些数据最终会以文件的形式反映在应用程序的私有数据文件夹(/data/data/)中。无论你使用哪个上下文,它们都将被映射到相同的文件夹/文件,所以没问题。

这就是我观察到的。也许在某些情况下你应该区分它们。

在某些情况下,当在线程中运行某些内容时,您可能会使用活动上下文而不是应用程序上下文。当线程完成执行并且需要将结果返回给调用者活动时,您需要具有处理程序的上下文。

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

我只使用这个和getBaseContext从一个onClick敬酒(非常绿色的新手到Java和android)。当我的点击器直接在活动中,并且必须在匿名的内部点击器中使用getBaseContext时,我使用这个。我猜这就是getBaseContext的诀窍,它可能返回隐藏内部类的活动的上下文。

几天前我读了这篇文章,问自己同样的问题。读完这篇文章后,我的决定很简单:始终使用applicationContext。

然而,我遇到了一个问题,我花了几个小时找到它,并在几秒钟解决它…(改变了一个词…)

我正在使用LayoutInflater来膨胀包含旋转器的视图。

所以这里有两种可能性:

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

然后,我做了这样的事情:

    // managing views part
View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
String[] myStringArray = new String[] {"sweet","love"};


// managing adapter part
// The context used here don't have any importance -- both work.
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);


theParentView.addView(view);

我注意到:如果你实例化你的线性布局与applicationContext,那么当你点击你的活动中的旋转器,你会有一个未捕获的异常,来自dalvik虚拟机(不是从你的代码,这就是为什么我花了很多时间来寻找哪里是我的错误…)

如果你使用baseContext,那么没关系,上下文菜单将打开,你将能够在你的选项中进行选择。

所以这是我的结论:我认为(我没有进一步测试)比baseContext是必需的处理上下文菜单在你的活动…

测试使用API 8进行编码,并在HTC Desire、android 2.3.3上进行测试。

希望我的评论到目前为止没有让你厌烦,祝你一切顺利。快乐编码;-)

下面是我发现的关于context的使用:

1)。Activity本身中,使用this来膨胀布局和菜单、注册上下文菜单、实例化小部件、启动其他活动、在Activity中创建新的Intent、实例化首选项或Activity中可用的其他方法。

膨胀布局:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

增加菜单:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.getMenuInflater().inflate(R.menu.mymenu, menu);
return true;
}

注册上下文菜单:

this.registerForContextMenu(myView);

实例化部件:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

启动Activity:

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

实例化偏好:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

2)。对于应用程序范围的类,使用getApplicationContext(),因为这个上下文在应用程序的生命周期中存在。

检索当前Android包的名称:

public class MyApplication extends Application {
public static String getPackageName() {
String packageName = null;
try {
PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
packageName = mPackageInfo.packageName;
} catch (NameNotFoundException e) {
// Log error here.
}
return packageName;
}
}

绑定一个应用范围的类:

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

3)。对于监听器和其他类型的Android类(例如contenttobserver),使用上下文替换如下:

mContext = this;    // Example 1
mContext = context; // Example 2

其中thiscontext是类(Activity等)的上下文。

Activity上下文替换:

public class MyActivity extends Activity {
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
}
}

侦听器上下文替换:

public class MyLocationListener implements LocationListener {
private Context mContext;
public MyLocationListener(Context context) {
mContext = context;
}
}

ContentObserver上下文替换:

public class MyContentObserver extends ContentObserver {
private Context mContext;
public MyContentObserver(Handler handler, Context context) {
super(handler);
mContext = context;
}
}

4)。对于BroadcastReceiver(包括内联/嵌入式接收器),使用接收器自己的上下文。

外部BroadcastReceiver:

public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
sendReceiverAction(context, true);
}
private static void sendReceiverAction(Context context, boolean state) {
Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
mIntent.putExtra("extra", state);
context.sendBroadcast(mIntent, null);
}
}
}

内联/嵌入式BroadcastReceiver:

public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
if (connected) {
// Do something.
}
}
};
}

5)。对于服务,使用服务自己的上下文。

public class MyService extends Service {
private BroadcastReceiver mBroadcastReceiver;
@Override
public void onCreate() {
super.onCreate();
registerReceiver();
}
private void registerReceiver() {
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
this.mBroadcastReceiver = new MyBroadcastReceiver();
this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
}
}

6)。对于toast,一般使用getApplicationContext(),但在可能的情况下,使用从活动、服务等传递的上下文。

使用应用程序的上下文:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

使用从源传递的上下文:

public static void showLongToast(Context context, String message) {
if (context != null && message != null) {
Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
mToast.show();
}
}

最后,不要像Android框架开发者建议的那样使用getBaseContext()

更新:添加Context用法示例。

简单地说

getApplicationContext()正如方法名称所暗示的那样,将使你的应用程序意识到你可以从应用程序的任何地方访问的应用程序范围的细节。因此,你可以在服务绑定、广播注册等中使用它。

getActivity()this将使你的应用程序意识到当前屏幕,这也是由application context提供的应用程序级别的详细信息。所以你想知道的关于当前屏幕的任何信息,比如Window ActionBar Fragementmanger等等,都可以通过这个上下文获得。基本上,Activity扩展了Context。在当前组件(活动)激活之前,该上下文都是激活的

这种混乱源于这样一个事实,即有许多方法来 access上下文,(表面上)没有明显的区别。 下面是四种最常见的方法

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

什么是Context? 我个人喜欢把上下文看作应用程序在任何给定时间的状态。应用程序上下文表示应用程序的全局或基本配置,活动或服务可以构建在它之上,并表示应用程序的配置实例或它的传递状态

看看android。content的源代码。Context,你可以看到Context是一个抽象类,类上的注释如下:

应用程序环境的全局信息接口。这是一个抽象类,它的实现由Android系统提供。它 允许对application-specific资源和类的访问,以及对application-level操作的向上调用,如启动活动、广播和接收意图等。 我从中得到的是Context提供了一个公共实现来访问应用程序级和系统级资源。应用程序级资源可以访问字符串资源[getResources()]或资产[getAssets()],系统级资源是你用Context.getSystemService().

访问的任何东西

事实上,看看这些方法的评论,它们似乎强化了这个概念:

getSystemService():按名称返回system-level服务的句柄。返回对象的类因请求的名称而异。 getResources():返回应用程序包的资源实例。 getAssets():返回应用程序包的资源实例。 值得指出的是,在Context抽象类中,上面所有的方法都是抽象的!只有一个getSystemService(类)实例具有调用抽象方法的实现。这意味着,这些的实现应该主要由实现类提供,包括:

ContextWrapper
Application
Activity
Service
IntentService

查看API文档,类的层次结构是这样的:

上下文

| - ContextWrapper

| - -应用

| - - ContextThemeWrapper

| - - -活动

| - -服务

| - - - IntentService

因为我们知道Context本身没有提供任何见解,所以我们沿着树向下移动,看看ContextWrapper,并意识到那里也没有什么。由于Application扩展了ContextWrapper,所以也没有太多需要注意的地方,因为它没有覆盖ContextWrapper提供的实现。这意味着Context的实现是由操作系统提供的,并且对API隐藏。您可以通过查看ContextImpl类的源代码来了解Context的具体实现。