Android 获取上下文的各种方法之间有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1026973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:37:03  来源:igfitidea点击:

What's the difference between the various methods to get a Context?

androidandroid-context

提问by Alnitak

In various bits of Android code I've seen:

在我见过的各种 Android 代码中:

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

However I can't find any decent explanation of which is preferable, and under what circumstances which should be used.

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

Pointers to documentation on this, and guidance about what might break if the wrong one is chosen, would be much appreciated.

关于这方面的文档的指针,以及关于如果选择错误的可能会破坏的指导,将不胜感激。

采纳答案by snctln

I agree that documentation is sparse when it comes to Contexts in Android, but you can piece together a few facts from various sources.

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

This blog poston the official Google Android developers blog was written mostly to help address memory leaks, but provides some good information about contexts as well:

本博客文章在谷歌官方Android开发者博客大部分是写来帮助解决内存泄漏,但提供了有关上下文一些有用的信息,以及:

In a regular Android application, you usually have two kinds of Context, Activity and Application.

在常规的 Android 应用程序中,通常有两种 Context,Activity 和 Application。

Reading the article a little bit further tells about the difference between the two and when you might want to consider using the application Context (Activity.getApplicationContext()) rather than using the Activity context this). Basically the Application context is associated with the Application and will always be the same throughout the life cycle of your app, where as the Activity context is associated with the activity and could possibly be destroyed many times as the activity is destroyed during screen orientation changes and such.

进一步阅读本文将了解两者之间的区别,以及您何时可能需要考虑使用应用程序 Context ( Activity.getApplicationContext()) 而不是使用 Activity context this)。基本上,应用程序上下文与应用程序相关联,并且在应用程序的整个生命周期中始终相同,因为 Activity 上下文与 Activity 相关联,并且可能会因 Activity 在屏幕方向更改期间被销毁而多次销毁,并且这样的。

I couldn't find really anything about when to use getBaseContext() other than a post from Dianne Hackborn, one of the Google engineers working on the Android SDK:

除了 Dianne Hackborn(一位从事 Android SDK 的 Google 工程师)的帖子之外,我找不到关于何时使用 getBaseContext() 的任何信息:

Don't use getBaseContext(), just use the Context you have.

不要使用 getBaseContext(),只需使用您拥有的 Context。

That was from a post on the android-developers newsgroup, you may want to consider asking your question there as well, because a handful of the people working on Android actual monitor that newsgroup and answer questions.

这是来自android-developers 新闻组的帖子,您可能也想考虑在那里提出您的问题,因为少数在 Android 上工作的人实际监视该新闻组并回答问题。

So overall it seems preferable to use the global application context when possible.

所以总的来说,如果可能的话,最好使用全局应用程序上下文。

回答by ChuongPham

Here's what I've found regarding the use of context:

这是我发现的关于使用的内容context

1) .Within an Activityitself, use thisfor inflating layouts and menus, register context menus, instantiating widgets, start other activities, create new Intentwithin an Activity, instantiating preferences, or other methods available in an Activity.

1)。在一个Activity本身,使用this了膨胀的布局和菜单,注册上下文菜单,实例化部件,启动其他活动,创造新的IntentActivity,中可用实例化偏好,或其他方法Activity

Inflate layout:

充气布局:

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

Inflate menu:

充气菜单:

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

Register context menu:

注册上下文菜单:

this.registerForContextMenu(myView);

Instantiate widget:

实例化小部件:

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

Start an Activity:

开始Activity

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

Instantiate preferences:

实例化首选项:

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

2) .For application-wide class, use getApplicationContext()as this context exist for the lifespan of the application.

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

Retrieve the name of the current Android package:

检索当前 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;
    }
}

Bind an application-wide class:

绑定一个应用程序范围的类:

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

3) .For Listeners and other type of Android classes (e.g. ContentObserver), use a Context substitution like:

3)。对于侦听器和其他类型的 Android 类(例如 ContentObserver),请使用 Context 替换,例如:

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

where thisor contextis the context of a class (Activity, etc).

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

Activitycontext substitution:

Activity上下文替换:

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

Listener context substitution:

监听器上下文替换:

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

ContentObservercontext substitution:

ContentObserver上下文替换:

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

4) .For BroadcastReceiver(including inlined/embedded receiver), use the receiver's own context.

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

External 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);
        }
    }
}

Inlined/Embedded BroadcastReceiver:

内联/嵌入式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) .For Services, use the service's own context.

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) .For Toasts, generally use getApplicationContext(), but where possible, use the context passed from an Activity, Service, etc.

6)。对于 Toast,通常使用getApplicationContext(),但在可能的情况下,使用从 Activity、Service 等传递的上下文。

Use context of the application:

使用应用程序的上下文:

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

Use context passed from a source:

使用从源传递的上下文:

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

And last, don't use getBaseContext()as advised by Android's framework developers.

最后,不要getBaseContext()按照 Android 框架开发人员的建议使用。

UPDATE:Add examples of Contextusage.

更新:添加Context用法示例。

回答by Mav3656

I read this thread a few days ago, asking myself the same question. My decision after reading this was simple: always use applicationContext.

几天前我读了这个帖子,问自己同样的问题。阅读本文后,我的决定很简单:始终使用 applicationContext。

However, I encountered a problem with this, I spent a few hours to find it, and a few seconds to solve it... (changing one word...)

然而,我遇到了这个问题,我花了几个小时才找到它,几秒钟就解决了它......(换一个词......)

I am using a LayoutInflater to inflate a view containing a Spinner.

我正在使用 LayoutInflater 来膨胀包含 Spinner 的视图。

So here are two possibilities:

所以这里有两种可能:

1)

1)

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

2)

2)

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

Then, I am doing something like this:

然后,我正在做这样的事情:

    // 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);

What I noticed: If you instantiated your linearLayout with the applicationContext, then when you click on the spinner in your activity, you will have an uncaught exception, coming from the dalvik virtual machine (not from your code, that's why I have spent a lot of time to find where was my mistake...).

我注意到了什么:如果你用 applicationContext 实例化你的 linearLayout,那么当你点击你的活动中的微调器时,你将有一个未捕获的异常,来自 dalvik 虚拟机(不是来自你的代码,这就是为什么我花了很多钱是时候找出我的错误在哪里了......)。

If you use the baseContext, then that's all right, the context menu will open and you will be able to choose among your choices.

如果您使用 baseContext,那就没问题了,上下文菜单将打开,您将能够在您的选择中进行选择。

So here is my conclusion: I suppose (I have not tested it further) than the baseContext is required when dealing with contextMenu in your Activity...

所以这是我的结论:我想(我没有进一步测试)比在你的活动中处理 contextMenu 时需要 baseContext ......

The test has been done coding with API 8, and tested on an HTC Desire, android 2.3.3.

测试已经用 API 8 完成编码,并在 HTC Desire,android 2.3.3 上测试。

I hope my comment have not bored you so far, and wish you all the best. Happy coding ;-)

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

回答by samsonsu

First, I agree that we should use appcontext whenever possible. then "this" in activity. i've never had a need for basecontext.

首先,我同意我们应该尽可能使用 appcontext。然后在活动中“这个”。我从来不需要basecontext。

In my tests, in most cases they can be interchanged. In most cases, the reason you want to get a hold of a context is to access files, preferences, database etc. These data is eventually reflected as files in your app's private data folder (/data/data/). No matter which context you use, they'll be mapped to the same folder/files so you are OK.

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

That's what I observed. Maybe there are cases you should distinguish them.

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

回答by Paul

In some cases you may use Activity context over application context when running something in a thread. When thread completes execution and you need to return the result back to the caller activity, you need that context with a handler.

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

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

回答by arjun

In simple words

简单来说

getApplicationContext()as the method name suggest will make your app aware of application wide details which you can access from anywhere in the app. So you can make use of this in service binding, broadcast registration etc. Application contextwill be alive till the app exits.

getApplicationContext()正如方法名称所暗示的那样,您的应用程序将了解您可以从应用程序的任何位置访问的应用程序范围的详细信息。所以你可以在服务绑定、广播注册等中使用它,Application context直到应用程序退出。

getActivity()or thiswill make your app aware of the current screen which is visible also the app level details provided by application context. So whatever you want to know about the current screen like WindowActionBarFragementmangerand so are available with this context. Basically and Activityextend Context. This context will alive till the current component(activity) is alive

getActivity()this将使您的应用了解当前屏幕,该屏幕也可见application context. 因此,无论您想了解当前屏幕的任何信息,WindowActionBarFragementmanger都可以在此上下文中使用。基本上和Activity扩展Context。此上下文将一直存在,直到当前组件(活动)处于活动状态

回答by Chanaka Weerasinghe

The confusion stems from the fact that there are numerous ways to access Context, with (on the surface) no discernible differences. Below are four of the most common ways you may be able to access Context in an Activity.

混淆源于这样一个事实,即访问 Context 的方法有很多种,(表面上)没有明显的差异。以下是您可以在活动中访问上下文的四种最常见方式。

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

What is a Context?I personally like to think of Context as the state of your application at any given time. The application Context represents a global or base configuration of your application and an Activity or Service can build upon it and represents a configuration instance of your Application or a transitive state for it.

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

If you look at the source for android.content.Context, you see that Context is an abstract class and the comments on the class are as follows:

如果查看android.content.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-specificresources and classes, as well as up-calls for application-leveloperations such as launching activities, broadcasting and receiving intents, etc. What I take away from this is that Context provides a common implementation to access application level as well as system level resources. Application level resources may be accessing things like String resources [getResources()]or assets [getAssets()]and system-level resource is anything that you access with Context.getSystemService().

有关应用程序环境的全局信息的接口。这是一个抽象类,其实现由Android系统提供。它允许访问application-specific资源和类,以及对application-level诸如启动活动、广播和接收意图等操作的向上调用。我从中得到的是,上下文提供了访问应用程序级别和系统级别的通用实现资源。应用程序级资源可能正在访问诸如字符串资源[getResources()]或资产之类的内容,[getAssets()]而系统级资源是您访问的任何内容Context.getSystemService().

As a matter of fact, take a look at the comments on the methods and they seem to reinforce this notion:

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

getSystemService(): Return the handle to a system-levelservice by name. The class of the returned object varies by the requested name. getResources(): Return a Resources instance for your application's package. getAssets(): Return a Resources instance for your application's package. It may be worth pointing out that in the Context abstract class, all of the above methods are abstract! Only one instance of getSystemService(Class) has an implementation and that invokes an abstract method. This means, the implementation for these should be provided mostly by the implementing classes, which include:

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

ContextWrapper
Application
Activity
Service
IntentService

Looking at the API documentation, the hierarchy of the classes looks like this:

查看 API 文档,类的层次结构如下所示:

Context

语境

|?—?ContextWrapper

|?—?ContextWrapper

|—?—?Application

|—?—?应用

|?—?— ContextThemeWrapper

|?—?— ContextThemeWrapper

|—?—?—?—?Activity

|—?—?—?—?活动

|?—?— Service

|?—?— 服务

|—?—?— IntentService

|—?—?— IntentService

Since we know that Contextitself is not providing any insight, we move down the tree and take a look at the ContextWrapperand realize that there isn't much there either. Since Application extends ContextWrapper, there isn't much to look at over there either since it doesn't override the implementation provided by ContextWrapper. This means that the implementation for Context is provided by the OS and is hidden from the API. You can take a look at the concrete implementation for Context by looking at the source for the ContextImpl class.

因为我们知道它Context本身并没有提供任何洞察力,所以我们沿着树向下移动并查看它ContextWrapper并意识到那里也没有太多东西。由于 Application extends ContextWrapper,那里也没有太多可看的,因为它没有覆盖ContextWrapper. 这意味着 Context 的实现是由操作系统提供的,并且对API. 您可以通过查看 ContextImpl 类的源代码来查看 Context 的具体实现。

回答by Tony

I've only used this and getBaseContextwhen toasting from an onClick(very green noob to both Java and android). I use this when my clicker is directly in the activity and have to use getBaseContextin an anonymous inner clicker. I'm guessing that is pretty much the trick with getBaseContext, it is perhaps returning the context of the activity in which the inner class is hiding.

我只用过这个,getBaseContext当从一个onClick(非常绿色的菜鸟到 Java 和 android)敬酒时。当我的答题器直接在活动中并且必须getBaseContext在匿名内部答题器中使用时,我会使用它。我猜这几乎是 的技巧getBaseContext,它可能会返回内部类隐藏的活动的上下文。