到处使用应用程序上下文?

在Android应用中,以下方法是否存在问题:

public class MyApp extends android.app.Application {


private static MyApp instance;


public MyApp() {
instance = this;
}


public static Context getContext() {
return instance;
}


}

并在需要上下文的地方传递它(例如SQLiteOpenHelper)(当然不泄漏)?

320517 次浏览

根据我的经验,这种方法是不必要的。如果你需要任何东西的上下文,你通常可以通过调用View.getContext ()来获得它,使用那里获得的Context,你可以调用Context.getApplicationContext ()来获得Application上下文。如果你试图从Activity中获得Application上下文,你总是可以调用Activity.getApplication (),它应该能够作为调用SQLiteOpenHelper()所需的Context传递。

总的来说,在这种情况下,你的方法似乎没有问题,但在处理Context时,只要确保你没有像官方谷歌Android开发者博客中描述的那样在任何地方泄漏内存。

这种方法有几个潜在的问题,尽管在很多情况下(比如您的例子)它会工作得很好。

特别是当你处理任何需要ContextGUI时,你应该非常小心。例如,如果你将应用上下文传递给Context0,你会得到一个异常。一般来说,你的方法是优秀的:在Context2中使用Context1,在将超出Context2范围的上下文传递给Context5时使用Context3是一个很好的实践。

同样,作为模式的替代,你可以使用对Context对象(例如活动)调用getApplicationContext()的快捷方式来获取应用程序上下文。

您正在尝试创建一个包装器来获取应用程序上下文,它可能会返回"null"指针。

根据我的理解,我猜更好的方法是调用- 2中的任何一个 Context.getApplicationContext()Activity.getApplication().

我喜欢它,但我建议改用单例:

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

我使用同样的方法,我建议把单例写得更好一点:

public static MyApp getInstance() {


if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}


return instance;
}

但我不是到处使用,我使用getContext()getApplicationContext(),我可以这样做!

这是一个很好的方法。我自己也用。我只建议重写onCreate来设置单例对象,而不是使用构造函数。

既然你提到了SQLiteOpenHelper:在onCreate ()中,你也可以打开数据库。

就我个人而言,我认为文档说通常不需要子类化Application是错误的。我认为恰恰相反:你应该总是子类化Application。

有人问:单例如何返回空指针? 我正在回答这个问题。(我不能在评论中回答,因为我需要发布代码。)

它可以在两个事件之间返回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);
}
}

让我们运行代码:

$ javac A.java
$ java A
x:X@a63599 y:Y@9036e
x:null y:null

第二行显示Y.xinstanceX.yinstance;它们是空的,因为变量X.xinstanceY.yinstance在它们为空时被读取。

这个问题可以解决吗?是的,

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

这段代码没有显示异常:

$ javac A.java
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e

这不是Android Application对象的一个选项:程序员不能控制创建它的时间。

同样:第一个示例和第二个示例之间的区别是,第二个示例在静态指针为空时创建一个实例。但是程序员不能在系统决定之前创建 Android应用程序对象。

更新

另一个令人困惑的例子,初始化的静态字段恰好是null

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

你会得到:

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull

注意,不能将静态变量声明往上移动一行,否则代码将无法编译。

我将使用应用程序上下文在构造函数中获取系统服务。这简化了测试。组合的好处

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类将使用重载构造函数。

Android将使用默认构造函数。

应用程序类:

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


}

在AndroidManifest中声明应用:

<application android:name=".MyApplication"
...
/>

用法:

MyApplication.getAppContext()

我知道最初的问题是13年前发布的,这是Kotlin版本的无处不在的上下文。

class MyApplication : Application() {
companion object {
@JvmStatic
private var instance: MyApplication? = null


@JvmStatic
public final fun getContext(): Context? {
return instance
}
}


override fun onCreate() {
instance = this
super.onCreate()
}
}