Android 到处使用应用程序上下文?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/987072/
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
Using Application context everywhere?
提问by yanchenko
In an Android app, is there anything wrong with the following approach:
在 Android 应用中,以下方法有什么问题吗:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
and pass it everywhere (e.g. SQLiteOpenHelper) where context is required (and not leaking of course)?
并将它传递到需要上下文的任何地方(例如 SQLiteOpenHelper)(当然不会泄漏)?
采纳答案by Reto Meier
There are a couple of potential problems with this approach, though in a lot of circumstances (such as your example) it will work well.
这种方法存在一些潜在的问题,但在很多情况下(例如您的示例)它会运行良好。
In particular you should be careful when dealing with anything that deals with the GUI
that requires a Context
. For example, if you pass the application Context into the LayoutInflater
you will get an Exception. Generally speaking, your approach is excellent: it's good practice to use an Activity's
Context
within that Activity
, and the Application Context
when passing a context beyond the scope of an Activity
to avoid memory leaks.
特别是在处理任何GUI
需要Context
. 例如,如果您将应用程序上下文传递到 中,LayoutInflater
您将得到一个异常。一般来说,您的方法非常好:Activity's
Context
在 that 中使用 an 是一种很好的做法Activity
,并且Application Context
when 传递超出 an 范围的上下文Activity
以避免内存泄漏。
Also, as an alternativeto your pattern you can use the shortcut of calling getApplicationContext()
on a Context
object (such as an Activity) to get the Application Context.
此外,作为一种替代你的方式,你可以使用电话的快捷键getApplicationContext()
一对Context
对象(如活动)来获取应用程序上下文。
回答by snctln
In my experience this approach shouldn't be necessary. If you need the context for anything you can usually get it via a call to View.getContext()and using the Context
obtained there you can call Context.getApplicationContext()to get the Application
context. If you are trying to get the Application
context this from an Activity
you can always call Activity.getApplication()which should be able to be passed as the Context
needed for a call to SQLiteOpenHelper()
.
根据我的经验,这种方法不应该是必要的。如果您需要任何内容的上下文,您通常可以通过调用View.getContext()来获取它,并使用Context
那里获得的内容,您可以调用Context.getApplicationContext()来获取Application
上下文。如果您想获得Application
从背景下,这个Activity
可以随时拨打Activity.getApplication()这应该可以作为传递Context
需要一个呼叫SQLiteOpenHelper()
。
Overall there doesn't seem to be a problem with your approach for this situation, but when dealing with Context
just make sure you are not leaking memory anywhere as described on the official Google Android Developers blog.
总的来说,您在这种情况下的方法似乎没有问题,但是在处理时,请Context
确保您没有按照官方Google Android 开发人员博客中的描述在任何地方泄漏内存。
回答by 18446744073709551615
Some people have asked: how can the singleton return a null pointer?I'm answering that question. (I cannot answer in a comment because I need to post code.)
有人问:单例怎么会返回空指针呢?我在回答那个问题。(我无法在评论中回答,因为我需要发布代码。)
It may return null in between two events: (1) the class is loaded, and (2) the object of this class is created. Here's an example:
它可能在两个事件之间返回 null:(1)类被加载,(2)这个类的对象被创建。下面是一个例子:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Let's run the code:
让我们运行代码:
$ javac A.java
$ java A
x:X@a63599 y:Y@9036e
x:null y:null
The second line shows that Y.xinstanceand X.yinstanceare null; they are null because the variables X.xinstanceans Y.yinstancewere read when they were null.
第二行显示Y.xinstance和X.yinstance为null;它们为空是因为变量X.xinstance和Y.yinstance在它们为空时被读取。
Can this be fixed? Yes,
这可以解决吗?是的,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
and this code shows no anomaly:
并且此代码没有显示异常:
$ javac A.java
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e
BUTthis is not an option for the Android Application
object: the programmer does not control the time when it is created.
但,这不是针对Android的选择Application
对象:在创建时,程序员不控制时间。
Once again: the difference between the first example and the second one is that the second example creates an instance if the static pointer is null. But a programmer cannot create theAndroid application object before the system decides to do it.
再说一遍:第一个示例和第二个示例之间的区别在于,如果静态指针为空,则第二个示例创建一个实例。但是,程序员不能创建的系统决定做之前,Android应用程序的对象。
UPDATE
更新
One more puzzling example where initialized static fields happen to be null
.
另一个令人费解的例子是,初始化的静态字段恰好是null
.
Main.java:
主.java:
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
And you get:
你会得到:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Note that you cannot move the static variable declaration one line upper, the code will not compile.
请注意,您不能将静态变量声明向上移动一行,代码将无法编译。
回答by toha
Application Class:
应用类:
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context mContext;
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getAppContext() {
return mContext;
}
}
Declare the Application in the AndroidManifest:
在 AndroidManifest 中声明应用程序:
<application android:name=".MyApplication"
...
/>
Usage:
用法:
MyApplication.getAppContext()
回答by Prasanta
You are trying to create a wrapper to get Application Context and there is a possibility that it might return "null
" pointer.
您正在尝试创建一个包装器来获取应用程序上下文,并且它有可能返回“ null
”指针。
As per my understanding, I guess its better approach to call- any of the 2
Context.getApplicationContext()
or Activity.getApplication()
.
根据我的理解,我想调用 2
Context.getApplicationContext()
或Activity.getApplication()
.
回答by Martin
It is a good approach. I use it myself as well. I would only suggest to override onCreate
to set the singleton instead of using a constructor.
这是一个很好的方法。我自己也用。我只建议覆盖onCreate
设置单例而不是使用构造函数。
And since you mentioned SQLiteOpenHelper
: In onCreate ()
you can open the database as well.
并且因为您提到SQLiteOpenHelper
:onCreate ()
您也可以在其中打开数据库。
Personally I think the documentation got it wrong in saying that There is normally no need to subclass Application. I think the opposite is true: You should always subclass Application.
就我个人而言,我认为文档错误地说通常不需要子类 Application。我认为恰恰相反:您应该始终子类化 Application。
回答by Blundell
I would use Application Context to get a System Service in the constructor. This eases testing & benefits from composition
我会使用应用程序上下文在构造函数中获取系统服务。这简化了测试并从组合中受益
public class MyActivity extends Activity {
private final NotificationManager notificationManager;
public MyActivity() {
this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
}
public MyActivity(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
// onCreate etc
}
Test class would then use the overloaded constructor.
然后测试类将使用重载的构造函数。
Android would use the default constructor.
Android 将使用默认构造函数。
回答by Franklin Pe?a
I like it, but I would suggest a singleton instead:
我喜欢它,但我建议改为单身:
package com.mobidrone;
import android.app.Application;
import android.content.Context;
public class ApplicationContext extends Application
{
private static ApplicationContext instance = null;
private ApplicationContext()
{
instance = this;
}
public static Context getInstance()
{
if (null == instance)
{
instance = new ApplicationContext();
}
return instance;
}
}
回答by Seraphim's
I'm using the same approach, I suggest to write the singleton a little better:
我正在使用相同的方法,我建议将单例写得更好一点:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
but I'm not using everywhere, I use getContext()
and getApplicationContext()
where I can do it!
但我没有在任何地方使用,我使用getContext()
和getApplicationContext()
我可以做到的地方!