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

时间:2009-06-22 12:38:15

标签: android android-context

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

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

然而,我找不到任何合适的解释,哪种更适合,以及在什么情况下应该使用。

指出有关此问题的文档,以及如果选择了错误选项可能会导致错误的指导,将不胜感激。

8 个答案:

答案 0 :(得分:301)

我同意在Android中的上下文中文档很少,但您可以将来自不同来源的一些事实拼凑起来。

官方Google Android开发者博客上的

This blog post主要是为了解决内存泄漏问题,但也提供了一些有关上下文的好信息:

  

在常规Android应用程序中,您   通常有两种Context,   活动与应用。

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

我找不到什么关于何时使用getBaseContext()的信息,而不是来自Dianne Hackborn的帖子,Dianne Hackborn是一位从事Android SDK工作的Google工程师:

  

不要使用getBaseContext(),只需使用   你拥有的语境。

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

总的来说,似乎最好尽可能使用全局应用程序上下文。

答案 1 :(得分:50)

以下是我发现的context

的使用方法

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

通胀布局:

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

2)。对于应用程序范围的类,请使用SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences(); ,因为此上下文存在于应用程序的生命周期中。

检索当前Android软件包的名称:

getApplicationContext()

绑定应用程序级别的课程:

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

3)。对于Listeners和其他类型的Android类(例如ContentObserver),请使用上下文替换,如:

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

其中mContext = this; // Example 1 mContext = context; // Example 2 this是类的上下文(Activity等)。

context上下文替换:

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

4)。对于public class MyContentObserver extends ContentObserver { private Context mContext; public MyContentObserver(Handler handler, Context context) { super(handler); mContext = context; } } (包括内联/嵌入式接收器),请使用接收者自己的上下文。

外部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

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

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.
            }
        }
    };
}

6)。对于Toasts,通常使用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); } } ,但在可能的情况下,请使用从Activity,Service等传递的上下文。

使用应用程序的上下文:

getApplicationContext()

使用从来源传递的上下文:

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

最后,请不要使用Android框架开发人员建议的public static void showLongToast(Context context, String message) { if (context != null && message != null) { Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG); mToast.show(); } }

更新:添加getBaseContext()用法的示例。

答案 2 :(得分:12)

我几天前读过这个帖子,问自己同样的问题。我在阅读之后做出的决定很简单:始终使用applicationContext。

然而,我遇到了这个问题,我花了几个小时找到它,并花了几秒钟来解决它......(改变一个字......)

我正在使用LayoutInflater来扩充包含Spinner的视图。

所以这里有两种可能性:

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实例化你的linearLayout,那么当你点击活动中的微调器时,你将有一个未捕获的异常来自dalvik虚拟机(不是来自你的代码,这就是为什么我有花了很多时间才找到我的错误......)。

如果您使用baseContext,那就没问题,上下文菜单将会打开,您可以在选择中进行选择。

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

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

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

答案 3 :(得分:6)

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

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

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

答案 4 :(得分:3)

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

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

答案 5 :(得分:2)

简单来说就是

getApplicationContext()作为方法名称建议会让您的应用了解应用范围内的详细信息,您可以从应用中的任何位置访问这些详细信息。所以你可以在服务绑定,广播注册等中使用它。Application context将一直存在,直到应用程序退出。

getActivity()this会让您的应用了解当前屏幕,该屏幕也显示application context提供的应用级详细信息。因此,无论您想了解当前屏幕如Window ActionBar Fragementmanger等,都可以使用此上下文。基本上Activity延长Context。这个上下文将一直存在,直到当前组件(活动)存活

答案 6 :(得分:0)

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

答案 7 :(得分:0)

  

混乱的根源在于存在多种方法   访问上下文,(从表面上看)没有明显区别。   以下是您可能会使用的四种最常见的方式   活动中的上下文。

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

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

如果您查看android.content.Context的源代码,则会发现Context是一个抽象类,对该类的注释如下:

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

事实上,请看一下有关方法的注释,它们似乎加强了这一概念:

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

ContextWrapper
Application
Activity
Service
IntentService

看看API文档,这些类的层次结构如下:

上下文

| — ContextWrapper

| — —应用程序

| — — ContextThemeWrapper

| — — — —活动

| — —服务

| — — — IntentService

由于我们知道Context本身并没有提供任何见识,因此我们将其移到树上,看看ContextWrapper并意识到那里也没有太多。由于应用程序扩展了ContextWrapper,因此在那边没有什么值得关注的,因为它没有覆盖ContextWrapper提供的实现。这意味着Context的实现由OS提供,并且对API隐藏。您可以通过查看ContextImpl类的源代码来查看Context的具体实现。