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

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

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

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


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

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

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

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.

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

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

这是来自Android开发人员新闻组的一篇帖子,你可能也想在那里问你的问题,因为有少数Android工作人员实际上在监控那个新闻组并回答问题。

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


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

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

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


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

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

我只使用这个和getBaseContext从一个onClick toast(非常绿色的新手到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上进行测试。

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


以下是我在使用语境方面的发现:

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

膨胀布局:

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

启动一个活动:

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

其中this或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;
    }
}

contenttobserver上下文替换:

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()。

更新:添加上下文使用示例。


简单地说

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

getActivity()或这将使你的应用程序意识到当前屏幕,这也是可见的应用程序上下文提供的应用程序级别的细节。你想知道的关于当前屏幕的任何东西比如Window ActionBar Fragementmanger都可以通过这个context得到。基本上和活动扩展上下文。在当前组件(活动)激活之前,该上下文都是激活的


造成这种困惑的原因是有很多方法 access上下文,(表面上)没有明显的区别。 下面是四种最常见的方法 活动中的上下文。

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

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

看看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-specific resources and classes, as well as up-calls for application-level operations 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().

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

getSystemService(): Return the handle to a system-level service 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:

ContextWrapper
Application
Activity
Service
IntentService

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

上下文

| - ContextWrapper

| - -应用

|— — 上下文主题包装器

| - - -活动

| - -服务

|— — 意图服务

Since we know that Context itself is not providing any insight, we move down the tree and take a look at the ContextWrapper and 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.