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

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

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


当前回答

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

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

其他回答

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

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

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

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

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

特别是在处理任何需要Context的GUI时,都应该非常小心。例如,如果你将应用Context传递给LayoutInflater,你会得到一个Exception。一般来说,您的方法是优秀的:在活动中使用活动的上下文,在传递超出活动范围的上下文时使用应用程序上下文,以避免内存泄漏,这是一个很好的实践。

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

我知道最初的问题是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()
    }
}

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

它可以在两个事件之间返回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为空;它们是空的,因为变量X.xinstance和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对象的一个选项:程序员不能控制创建它的时间。

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

更新

还有一个令人困惑的例子,初始化的静态字段恰好为空。

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

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