490

在Android应用程序中,以下方法有什么问题:

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

并将它传递到需要上下文的任何地方(例如SQLiteOpenHelper)(当然不会泄漏)?

4

9 回答 9

427

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

特别是在处理GUI需要Context. 例如,如果您将应用程序上下文传递给LayoutInflater您将得到一个异常。一般来说,您的方法非常好:Activity's Context在 that中使用 an 是一种很好的做法Activity,并且Application Context在传递超出 an 范围的上下文Activity避免内存泄漏时。

此外,作为模式的替代方案,您可以使用调用对象(例如 Activity)的快捷方式来获取应用程序上下文getApplicationContext()Context

于 2009-06-12T16:00:30.393 回答
30

以我的经验,这种方法不应该是必要的。如果您需要任何内容​​的上下文,您通常可以通过调用View.getContext()来获取它,并使用在Context那里获得的内容,您可以调用Context.getApplicationContext()来获取Application上下文。如果您试图Application从 an 获取上下文,Activity您可以随时调用Activity.getApplication(),它应该能够作为Context调用所需的SQLiteOpenHelper().

总体而言,您在这种情况下的方法似乎没有问题,但是在处理时,Context请确保您没有在任何地方泄漏内存,如官方Google Android 开发人员博客中所述。

于 2009-06-12T15:57:54.393 回答
14

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

它可能会在两个事件之间返回 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.yinstancenull;它们为空,因为变量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

但这不是 AndroidApplication对象的选项:程序员不控制创建它的时间。

再次重申:第一个示例和第二个示例之间的区别在于,如果静态指针为空,则第二个示例创建一个实例。但是程序员不能在系统决定之前创建Android应用程序对象。

更新

另一个令人费解的例子是初始化的静态字段恰好是null.

主.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

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

于 2013-12-09T06:17:20.657 回答
12

应用类:

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()
于 2016-08-13T10:37:44.237 回答
8

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

根据我的理解,我想它更好地调用 2 Context.getApplicationContext()Activity.getApplication().

于 2010-06-21T06:55:20.543 回答
5

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

既然你提到SQLiteOpenHelperonCreate ()你也可以打开数据库。

就我个人而言,我认为文档说通常没有必要继承 Application 是错误的。我认为恰恰相反:你应该总是继承 Application。

于 2013-08-07T12:46:20.830 回答
3

我会使用应用程序上下文在构造函数中获取系统服务。这简化了测试并从组合中受益

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 将使用默认构造函数。

于 2014-06-27T08:45:49.323 回答
1

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

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;
    }
}
于 2011-02-23T22:49:33.077 回答
0

我正在使用相同的方法,我建议将单例写得更好一点:

public static MyApp getInstance() {

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

    return instance;
}

但我不是在任何地方都使用,我使用getContext()并且getApplicationContext()在哪里可以做到!

于 2013-06-05T13:52:01.537 回答