Android 到处使用应用程序上下文?
在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; } } 并在需要上下
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()