在Android应用中,以下方法有什么问题:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
并将其传递到任何地方(例如SQLiteOpenHelper),其中需要上下文(当然不会泄漏)?
答案 0 :(得分:399)
这种方法存在一些潜在的问题,但在很多情况下(例如你的例子)它会很好用。
特别是在处理需要 GUI
的 Context
的任何内容时,请务必小心。例如,如果您将应用程序上下文传递到 LayoutInflater
,您将收到异常。一般来说,您的方法非常出色:在 Activity's
中使用 Context
Activity
,以及 Application Context
的范围传递给avoid memory leaks时,<{1}} 。
此外,作为模式的替代,您可以使用在 Activity
对象(例如活动)上调用getApplicationContext()
的快捷方式)获取应用程序上下文。
答案 1 :(得分:28)
根据我的经验,这种方法不应该是必要的。如果您需要任何上下文,通常可以通过调用View.getContext()并使用在那里获得的Context来获取它,您可以调用Context.getApplicationContext()来获取应用程序上下文。如果您尝试从活动中获取Appication上下文,您可以随时调用Activity.getApplication(),它应该能够作为调用SQLiteOpenHelper()所需的上下文传递
总的来说,对于这种情况,您的方法似乎没有问题,但在处理Context时,请确保您没有按照官方Google Android Developers blog
中所述的任何地方泄漏内存答案 2 :(得分:12)
有些人问过: 单例如何返回空指针? 我正在回答这个问题。 (我无法在评论中回答,因为我需要发布代码。)
它可能在两个事件之间返回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.xinstance 和 X.yinstance null ;它们为null,因为变量 X.xinstance ans Y.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
对象的选项:程序员无法控制创建它的时间。
再次:第一个示例和第二个示例之间的区别在于,如果静态指针为null,则第二个示例创建一个实例。但是程序员在系统决定之前无法创建 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
请注意,您不能将静态变量声明移到上一行,代码将无法编译。
答案 3 :(得分:9)
您正在尝试创建一个包装器以获取应用程序上下文,并且它可能会返回“null
”指针。
根据我的理解,我猜它是更好的方法来调用2中的任何一个
Context.getApplicationContext()
或Activity.getApplication()
。
答案 4 :(得分:9)
申请类:
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()
答案 5 :(得分:4)
这是一个很好的方法。我自己也用它。我只建议覆盖onCreate
来设置单例,而不是使用构造函数。
自从您提到SQLiteOpenHelper
后:在onCreate ()
中,您也可以打开数据库。
我个人认为文档说错了通常不需要子类Application 。我认为情况恰恰相反:你应该总是将Application子类化。
答案 6 :(得分:3)
我会使用Application Context在构造函数中获取系统服务。这简化了测试和组成带来的好处
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
}
然后,测试类将使用重载的构造函数。
Android将使用默认构造函数。
答案 7 :(得分:1)
静态定义上下文会导致内存泄漏
到处获取上下文的标准方法:
public class App extends Application {
public static transient SoftReference<Context> contextReference;
@Override
public void onCreate() {
super.onCreate();
contextReference = new SoftReference<Context>(getApplicationContext());
}
}
通过这种方式,您将在代码中的任何地方拥有上下文 像这样:
App.contextReference.get();
任何其他方式都会降低性能并导致内存泄漏
希望有用...
答案 8 :(得分:0)
我喜欢它,但我建议改为使用单身人士:
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;
}
}
答案 9 :(得分:0)
我使用相同的方法,我建议更好地编写单例:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
但我没有在任何地方使用,我使用getContext()
和getApplicationContext()
我可以做到这一点!