安卓全局变量

327

我该如何创建全局变量,使其在应用程序的生命周期内保持值不变,而不管运行哪个活动。


为什么我们应该使用set和get(Jeff Gilfelt的答案)?!为什么我们不能直接将值设置到变量中,例如:public volatile static String x; 要设置值:GeneralClass.x = value; - Dr.jacky
14个回答

584

您可以扩展基础android.app.Application类并像此处一样添加成员变量:

public class MyApplication extends Application {

    private String someVariable;

    public String getSomeVariable() {
        return someVariable;
    }

    public void setSomeVariable(String someVariable) {
        this.someVariable = someVariable;
    }
}

在你的Android清单文件中,你必须声明实现android.app.Application的类(将android:name=".MyApplication"属性添加到现有的application标签中):

<application 
  android:name=".MyApplication" 
  android:icon="@drawable/icon" 
  android:label="@string/app_name">

然后在您的活动中,您可以这样获取和设置变量:

// set
((MyApplication) this.getApplication()).setSomeVariable("foo");

// get
String s = ((MyApplication) this.getApplication()).getSomeVariable();

4
太棒了,您的帮助让我受益匪浅。 - d-man
6
很遗憾,它对我没有用。请确认此后我们在清单中将有两个<application>标签。对吗?因为有些地方听说要将此添加到现有的应用程序标签中。请帮忙! - Adil Malik
9
你需要在现有的<application>标签中添加android:name标签。 - Marijn
64
这不应该是正确的答案,因为它可能会导致意外行为并由于内存清理而导致NPE。http://www.developerphil.com/dont-store-data-in-the-application-object/ (注意:为了在保持原意的同时使翻译更加通俗易懂,我略微调整了句子结构和用词) - bakua
4
我同意@bakua的看法。我们不应期望无论何时我们的应用在后台运行时,当Android缺少内存时它不会被终止。 - Oskar
显示剩余14条评论

44

你可以像这样使用单例模式

package com.ramps;

public class MyProperties {
private static MyProperties mInstance= null;

public int someValueIWantToKeep;

protected MyProperties(){}

public static synchronized MyProperties getInstance() {
        if(null == mInstance){
            mInstance = new MyProperties();
        }
        return mInstance;
    }
}

在您的应用程序中,您可以通过以下方式访问单例:

MyProperties.getInstance().someValueIWantToKeep

32
如果应用程序暂停,用户开始了另一个应用程序并且此时内存不足,Android会在用户恢复应用程序时移除静态对象,导致静态引用为空。 - d-man
5
一个静态变量在不同进程的活动之间是无用的。 - ateiob
4
如果你的实例被垃圾回收了,这段代码就不起作用了。因此,如果(null == mInstance) 的部分代码可以正常工作,那么新的实例将被返回,这将重置属性。 - Lalith B
1
@Mr.Hyde 单例模式不是没用的,只要我们知道在单例模式中应该存放什么东西。如果我们将大型位图数组或一些集合放入其中,则可能会变得危险。请注意在单例模式内部存放的内容。 - Lalith B
1
我知道我有点晚了,但对于未来的读者,我们可以将值存储在SharedPreferences、SQLLite数据库或内部存储文件中。这些都将具有数据持久性,即使应用程序关闭也是如此。 - powernit
显示剩余3条评论

17

这个全局变量适用于我的项目:

public class Global {
    public static int ivar1, ivar2;
    public static String svar1, svar2;
    public static int[] myarray1 = new int[10];
}


//  How to use other or many activity
Global.ivar1 = 10;

int i = Global.ivar1;

2
但是你如何将它传递给多个活动? - Zapnologica
18
当应用程序被挂起且设备内存不足时,Android虚拟机可能会将这些静态数据(至少包括字符串和数组)清空。请注意,翻译保持原意,并尽量简明易懂。 - Anton
4
@mahasam,我认为静态方法可能不是正确的方式...如果只涉及到activities,应该使用Application context。否则,可以采用其他答案中提供的单例模式。静态方法将会让代码紧密耦合,并且也会降低可测试性。 - Punith Raj

15

您可以使用应用首选项。只要传递Context对象,它们就可以从任何活动或代码片段中访问,并且它们对使用它们的应用程序是私有的,因此您不必担心暴露特定于应用程序的值,除非您处理路由设备。即使如此,您也可以使用哈希或加密方案保存这些值。此外,这些首选项存储在应用程序运行到下一次之间。

这里有一些代码示例供您查看。

我已经更新了链接。该项目曾经托管在Google Code上,但我们知道它已经关闭了。现在的链接来自Github。 - r1k0

12

使用SharedPreferences来存储和检索全局变量。

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String userid = preferences.getString("userid", null);

考虑到可靠性、隐私和其他应用程序的不可访问性,这应该得到点赞。 - PravyNandas
1
他们需要生命周期变量。即使应用程序被杀死,共享首选项也会被保存。 - Zahra

8

您想要的内容有几种不同的实现方式。

1.) 扩展应用程序类并在其中实例化控制器和模型对象。

public class FavoriteColorsApplication extends Application {

    private static FavoriteColorsApplication application;
    private FavoriteColorsService service;

    public FavoriteColorsApplication getInstance() {
        return application;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        application = this;
        application.initialize();
    }

    private void initialize() {
        service = new FavoriteColorsService();
    }

    public FavoriteColorsService getService() {
        return service;
    }

}

那么您随时可以从自定义应用程序对象中调用您的单例:
public class FavoriteColorsActivity extends Activity {

private FavoriteColorsService service = null;
private ArrayAdapter<String> adapter;
private List<String> favoriteColors = new ArrayList<String>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_favorite_colors);

    service = ((FavoriteColorsApplication) getApplication()).getService();
    favoriteColors = service.findAllColors();

    ListView lv = (ListView) findViewById(R.id.favoriteColorsListView);
    adapter = new ArrayAdapter<String>(this, R.layout.favorite_colors_list_item,
            favoriteColors);
    lv.setAdapter(adapter);
}

2.) 您可以让控制器创建一个单例实例:

public class Controller {
    private static final String TAG = "Controller";
    private static sController sController;
    private Dao mDao;

    private Controller() {
        mDao = new Dao();    
    }

    public static Controller create() {
        if (sController == null) {
            sController = new Controller();
        }
        return sController;
    }
}

然后您可以从任何活动或片段中调用create方法,如果尚未存在控制器,则会创建新的控制器,否则将返回预先存在的控制器。

3.) 最后,有一个由Square创建的精简框架,在Android内提供依赖注入。它被称为Dagger。我不会在这里解释如何使用它,但如果您需要这种东西,它非常好用。

希望我已经详细说明了您所希望的内容。


6

请尝试以下方法:

创建一个共享数据类:

SharedData.java

import android.app.Application;

/**
 * Created by kundan on 6/23/2015.
 */
public class Globals {


    private static Globals instance = new Globals();

    // Getter-Setters
    public static Globals getInstance() {
        return instance;
    }

    public static void setInstance(Globals instance) {
        Globals.instance = instance;
    }

    private String notification_index;


    private Globals() {

    }


    public String getValue() {
        return notification_index;
    }


    public void setValue(String notification_index) {
        this.notification_index = notification_index;
    }



}

在那些你想设置/获取数据的类中,全局声明/初始化一个类实例(在onCreate()方法之前使用以下代码):
Globals sharedData = Globals.getInstance();

设置数据:

sharedData.setValue("kundan");

获取数据:

String n = sharedData.getValue();

4
您可以像这样创建一个全局类:

Global Class

public class GlobalClass extends Application{

    private String name;
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String aName) {
        name = aName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String aEmail) {
        email = aEmail;
    }
}

然后在清单文件中定义它:
<application
    android:name="com.example.globalvariable.GlobalClass" ....

现在您可以像这样设置全局变量的值:
final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
globalVariable.setName("Android Example context variable");

您可以这样获取这些值:
final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
final String name  = globalVariable.getName();

请在此博客中查找完整的示例:全局变量或应用程序上下文变量 - Android示例。 (链接)

如果我在Activity中写了“final GlobalClass globalVariable = (GlobalClass) getApplicationContext();”,会出现无法转换为application.Global的异常。 - Gyan Swaroop Awasthi
这不是一个很好的方法,因为每次都需要上下文来获取应用程序上下文。 - htafoya

4
我检查了类似的答案,但这些答案不符合我的需求。我发现有一些东西,从我的角度来看,这就是你要找的东西。唯一可能的问题是安全问题(或者也许不是),因为我对安全并不了解。
我建议使用接口(不需要使用带构造函数等的类),因为您只需要创建类似以下的内容:
public interface ActivityClass {

    public static final String MYSTRING_1 = "STRING";

    public static final int MYINT_1 = 1;

}

然后你可以通过以下方式在类中访问到任何地方:

int myInt = ActivityClass.MYINT_1;
String myString = ActivityClass.MYSTRING_1;

4
// My Class Global Variables  Save File Global.Java
public class Global {
    public static int myVi; 
    public static String myVs;
}

// How to used on many Activity

Global.myVi = 12;
Global.myVs = "my number";
........
........
........
int i;
int s;
i = Global.myVi;
s = Global.myVs + " is " + Global.myVi;

1
你为什么在同一个问题中发布两个答案?你可以将它编辑成一个。 - Kunu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接