What's the difference between the various methods to get a Context?
在各种各样的Android代码中,我看到了:
1 2 3 4 5 6 7 | public class MyActivity extends Activity { public void method() { mContext = this; // since Activity extends Context mContext = getApplicationContext(); mContext = getBaseContext(); } } |
但是我找不到任何合适的解释,最好是哪种解释,以及在什么情况下应该使用哪种解释。
如果选择了错误的一个,那么对于这方面的文档以及关于可能会破坏什么的指导将是非常感激的。
我同意,在Android环境中,文档很少,但您可以从各种来源拼凑出一些事实。
谷歌Android开发者官方博客上的这篇博客文章主要是为了帮助解决内存泄漏问题,但也提供了一些关于上下文的好信息:
In a regular Android application, you
usually have two kinds of Context,
Activity and Application.
进一步阅读这篇文章可以了解到这两者之间的区别,以及您可能希望考虑何时使用应用程序上下文(
除了Dianne Hackborn的帖子之外,我真的找不到任何关于何时使用getBaseContext()的信息,Dianne Hackborn是一位致力于Android SDK的谷歌工程师:
Don't use getBaseContext(), just use
the Context you have.
这是来自安卓开发者新闻组的一篇文章,你可能也要考虑在那里问你的问题,因为在安卓开发者新闻组工作的少数人会监控该新闻组并回答问题。
因此,总的来说,如果可能的话,最好使用全局应用程序上下文。
以下是我在使用
1)。在
充气布局:
1 | View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup); |
充气菜单:
1 2 3 4 5 6 | @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); this.getMenuInflater().inflate(R.menu.mymenu, menu); return true; } |
注册上下文菜单:
1 | this.registerForContextMenu(myView); |
实例化小部件:
1 | TextView myTextView = (TextView) this.findViewById(R.id.myTextView); |
启动
1 2 | Intent mIntent = new Intent(this, MyActivity.class); this.startActivity(mIntent); |
实例化首选项:
1 | SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences(); |
2)。对于应用程序范围的类,使用
检索当前Android软件包的名称:
1 2 3 4 5 6 7 8 9 10 11 12 | 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; } } |
绑定应用程序范围类:
1 2 3 4 5 | Intent mIntent = new Intent(this, MyPersistent.class); MyServiceConnection mServiceConnection = new MyServiceConnection(); if (mServiceConnection != null) { getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE); } |
3)。对于侦听器和其他类型的Android类(例如ContentObserver),使用上下文替换,如:
1 2 | mContext = this; // Example 1 mContext = context; // Example 2 |
其中
1 2 3 4 5 6 7 8 | public class MyActivity extends Activity { private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; } } |
侦听器上下文替换:
1 2 3 4 5 6 | public class MyLocationListener implements LocationListener { private Context mContext; public MyLocationListener(Context context) { mContext = context; } } |
1 2 3 4 5 6 7 | public class MyContentObserver extends ContentObserver { private Context mContext; public MyContentObserver(Handler handler, Context context) { super(handler); mContext = context; } } |
4)。对于
外部
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } } } |
嵌入式/嵌入式
1 2 3 4 5 6 7 8 9 10 11 | 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)。对于服务,使用服务自己的上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)。对于祝酒词,通常使用
使用应用程序上下文:
1 2 | Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG); mToast.show(); |
使用从源传递的上下文:
1 2 3 4 5 6 | public static void showLongToast(Context context, String message) { if (context != null && message != null) { Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG); mToast.show(); } } |
最后,不要按照安卓框架开发人员的建议使用
更新:添加
几天前我读了这篇文章,问自己同样的问题。阅读后我的决定很简单:总是使用applicationContext。
然而,我遇到了一个问题,我花了几个小时找到它,并用几秒钟来解决它…(更改一个词…)
我正在使用一个布局充气器来充气包含旋转器的视图。
所以有两种可能性:
1)
1 | LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext()); |
2)
1 | LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext()); |
然后,我在做这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 | // 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,那么就可以打开上下文菜单,在您的选择中进行选择。
所以我的结论是:我想(我没有做过进一步的测试)在您的活动中处理contextmenu时需要basecontext。
该测试已经用api 8进行了编码,并在HTC要求的android 2.3.3上进行了测试。
我希望我的评论不会让你感到厌烦,并祝你一切顺利。快乐编码;-)
首先,我同意我们应该尽可能使用AppContext。然后在活动中"这个"。我从来就不需要basecontext。
在我的测试中,大多数情况下它们可以互换。在大多数情况下,您想要获取上下文的原因是访问文件、首选项、数据库等。这些数据最终会反映为应用程序的私有数据文件夹(/data/data/)中的文件。无论您使用哪个上下文,它们都将映射到同一个文件夹/文件,这样您就可以了。
这就是我观察到的。也许有些情况你应该加以区分。
在某些情况下,在线程中运行某些内容时,可以在应用程序上下文上使用活动上下文。当线程完成执行,并且您需要将结果返回到调用方活动时,您需要一个带有处理程序的上下文。
1 | ((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...); |
用简单的话
我只使用这个和EDCOX1 2当从EDCOX1的3个词(非常绿色NOOB到JAVA和Android)烘焙。当我的点击器直接在活动中,并且必须在匿名内部点击器中使用