402

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

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

但是,我找不到任何合适的解释来说明哪个更可取,以及在什么情况下应该使用哪个。

非常感谢有关这方面的文档的指针,以及有关如果选择了错误的文档可能会导致什么问题的指导,我们将不胜感激。

4

8 回答 8

312

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

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

在一个普通的Android应用中,你通常有两种Context,Activity和Application。

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

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

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

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

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

于 2009-06-22T14:11:24.700 回答
55

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

1) 。在 an 内部,Activity用于this扩展布局和菜单、注册上下文菜单、实例化小部件、启动其他活动、在.IntentActivityActivity

充气布局:

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) 。对于 Listeners 和其他类型的 Android 类(例如 ContentObserver),请使用 Context 替换,例如:

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

where thisorcontext是类的上下文(活动等)。

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(),但在可能的情况下,使用从 Activity、Service 等传递的上下文。

使用应用程序的上下文:

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

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

更新:添加使用示例Context

于 2012-12-19T04:43:40.140 回答
13

几天前我读了这个帖子,问自己同样的问题。阅读后我的决定很简单:始终使用 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 上进行了测试。

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

于 2012-01-06T17:14:49.270 回答
6

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

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

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

于 2010-03-20T08:48:21.677 回答
3

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

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
于 2010-09-24T23:29:29.740 回答
2

简单来说

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

getActivity()this将使您的应用程序知道当前屏幕,该屏幕也可见,提供的应用程序级别详细信息application context。因此,无论您想了解有关当前屏幕的任何信息,Window ActionBar Fragementmanger都可以在此上下文中使用。基本上和Activity扩展Context。此上下文将一直存在,直到当前组件(活动)处于活动状态

于 2017-02-09T12:49:16.020 回答
1

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

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

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

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

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

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

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

ContextWrapper
Application
Activity
Service
IntentService

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

语境

| — 上下文包装器

|— — 应用

| — — ContextThemeWrapper

|— — — — 活动

| - - 服务

|— — — IntentService

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

于 2019-07-02T07:48:03.310 回答
0

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

于 2011-12-12T17:02:36.227 回答