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

Android 到处使用应用程序上下文?,android,android-context,Android,Android Context,在Android应用程序中,以下方法是否有问题: public class MyApp extends android.app.Application { private static MyApp instance; public MyApp() { instance = this; } public static Context getContext() { return instance; } } 并在需要上下

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

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

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

根据我的经验,这种方法不应该是必要的。如果您需要任何内容的上下文,通常可以通过调用并使用从那里获得的
上下文
来获取上下文,您可以调用以获取
应用程序
上下文。如果您试图从
活动获取
应用程序
上下文,则始终可以调用它,该调用应该能够作为调用
SQLiteOpenHelper()
所需的
上下文
传递


总的来说,在这种情况下,您的方法似乎没有问题,但在处理
上下文时,只需确保您没有像官方描述的那样在任何地方泄漏内存。

这种方法存在一些潜在问题,尽管在很多情况下(例如您的示例)它将很好地工作

在处理任何需要
上下文的
时,尤其要小心。例如,如果将应用程序上下文传递到
LayoutInflater
中,则会出现异常。一般来说,您的方法是优秀的:在
活动中使用
活动的
上下文
是一种良好的做法,当将
活动范围以外的上下文传递给
时,使用
应用程序上下文
是一种很好的做法


此外,作为模式的一种替代方法,您可以在
上下文
对象(例如活动)上使用调用
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;
    }
}

我使用相同的方法,我建议将singleton编写得更好一些:

public static MyApp getInstance() {

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

    return instance;
}

但我并不是到处都使用,我使用
getContext()
getApplicationContext()
在我可以使用的地方

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

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


就我个人而言,我认为文档说通常不需要对应用程序进行子类化是错误的。我认为情况正好相反:您应该始终将应用程序子类化。

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

在两个事件之间,它可能返回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,因为变量X.xinstance和Y.yinstance在为null时被读取

这个问题能解决吗?对

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
应用程序
对象的选项:程序员不控制创建它的时间

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

更新

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

Main.java:

enum MyEnum{
第一,第二;
私有静态字符串前缀=”;
字符串myName;
髓鞘(){
myName=makeMyName();
}
字符串makeMyName(){
返回前缀+名称()+后缀;
}
字符串getMyName(){
返回我的名字;
}
}
公共班机{
公共静态void main(字符串参数[]){
System.out.println(“第一个:+MyEnum.first+”第二个:+MyEnum.second”);
System.out.println(“第一个:+MyEnum.first.makeMyName()+”第二个:+MyEnum.second.makeMyName());
System.out.println(“第一个:+MyEnum.first.getMyName()+”第二个:+MyEnum.second.getMyName());
}
}
你会得到:

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
$javac Main.java
$java Main
第一:第一:第二:第二
第一:第二:
第一个:nullFIRSTnull第二个: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

}
然后,测试类将使用重载构造函数

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"
    ...
/>

谢谢你给我一个鼓舞人心的答案。我想我将只在持久层使用这种方法(因为我不想使用内容提供商)。想知道设计SQLiteOpenHelper的动机是什么,它希望提供上下文,而不是从应用程序本身获取上下文。还有,你的书很棒!将应用程序上下文与
LayoutInflator
配合使用对我来说很有效。必须在过去三年中进行了更改。@JacobPhillips使用LayoutInflator而不使用活动上下文将错过该活动的样式设置。所以它在某种意义上是可行的,但在某种意义上是行不通的
<application android:name=".MyApplication"
    ...
/>
MyApplication.getAppContext()