Zmienna globalna dla systemu Android

293

Jak mogę utworzyć zmienną globalną, zachowaj wartości przez cały cykl życia aplikacji, niezależnie od tego, które działanie jest uruchomione.

d-man
źródło
I dlaczego powinniśmy używać set and get (odpowiedź Jeffa Gilfelt'a) ?! Dlaczego po prostu ustawiamy wartość bezpośrednio na zmienną? jak to: public volatile static String x; i aby ustawić wartość: GeneralClass.x = wartość;
Dr.jacky

Odpowiedzi:

531

Możesz rozszerzyć android.app.Applicationklasę podstawową i dodać zmienne składowe w następujący sposób:

public class MyApplication extends Application {

    private String someVariable;

    public String getSomeVariable() {
        return someVariable;
    }

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

W manifeście Androida musisz zadeklarować klasę implementującą android.app.Application (dodaj android:name=".MyApplication"atrybut do istniejącego znacznika aplikacji):

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

Następnie w swoich działaniach możesz uzyskać i ustawić zmienną w następujący sposób:

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

// get
String s = ((MyApplication) this.getApplication()).getSomeVariable();
Jeff Gilfelt
źródło
4
świetna pomoc, naprawdę aplikuję.
d-man
6
Niestety to nie działa dla mnie. Potwierdź, że po tym będziemy manifestować dwa tagi <application>. Dobrze? Ponieważ w niektórych miejscach słyszałem ludzi mówiących, że musimy dodać to do istniejącego tagu aplikacji. Proszę pomóż !!
Adil Malik,
9
@AdilMalik Musisz dodać Androida: tag do istniejącego tagu aplikacji
Marijn
2
Dlaczego nie stworzyć klasy z publicznymi polami statycznymi bez potrzeby dostępu do kontekstu?
Laserson
50
To nie powinna być poprawna odpowiedź, ponieważ może prowadzić do nieprzewidzianych zachowań i NPE z powodu czyszczenia pamięci. developerphil.com/dont-store-data-in-the-application-object
bakua
43

Możesz użyć Singleton Patterntakiego:

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

W aplikacji możesz uzyskać dostęp do singletona w następujący sposób:

MyProperties.getInstance().someValueIWantToKeep
Rampy
źródło
28
Co się stanie, jeśli aktywność zostanie wstrzymana, a użytkownik uruchomi inną aplikację i podczas tego okresu pamięci będzie mało, dlatego Android usunął ten obiekt statyczny, gdy użytkownik wznowi aplikację i stwierdzi, że to odniesienie statyczne jest puste?
d-man
4
Statyczny jest bezużyteczny dla różnych działań w oddzielnych procesach.
ateiob
3
to nie zadziała, jeśli twoja instancja jest śmieciami. więc blok kodu if (null == mInstance) {mInstance = new MyProperties (); } będzie działać i zostanie zwrócona nowa instancja, która zresetuje właściwości
Lalith B
1
@ Mr.Hyde Singleton nie jest bezużyteczny, po prostu musimy wiedzieć, co zachować w Singleton. Jeśli przechowujemy ogromną tablicę bitmap lub niektóre kolekcje, może to stać się niebezpieczne. Zwróć uwagę na to, co trzymasz w Singleton.
Lalith B,
1
Wiem, że jestem trochę spóźniony, ale dla przyszłych czytelników możemy przechowywać wartości w SharedPreferences, SQLLite Database lub An Internal memory file. Wszystkie te będą miały trwałość danych, nawet jeśli aplikacja zostanie zamknięta.
powernit
15

Ta zmienna globalna działa w moim projekcie:

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;
Mahasam
źródło
2
Ale w jaki sposób przekazujesz to do wielu działań?
Zapnologica,
15
Te statystyki (przynajmniej łańcuch i tablica) mogą zostać unieważnione przez maszynę wirtualną z systemem Android, gdy aplikacja jest zawieszona, a urządzenie ma mało pamięci.
Anton
4
@mahasam Nie sądzę, że statyczny powinien być właściwą drogą ... jeśli to jedyne działania, powinien to być kontekst aplikacji. W inny sposób, jak podano w innych odpowiedziach powyżej. static silnie połączy kod, a także zmniejszy testowalność
Punith Raj
14

Możesz użyć preferencji aplikacji. Są one dostępne z dowolnego działania lub fragmentu kodu, o ile przekazujesz obiekt Context, i są prywatne dla aplikacji, która ich używa, więc nie musisz się martwić o ujawnienie wartości specyficznych dla aplikacji, chyba że zajmujesz się routingiem urządzenia. Mimo to możesz użyć schematów mieszania lub szyfrowania, aby zapisać wartości. Preferencje te są również przechowywane od uruchomienia aplikacji do następnego. Oto kilka przykładów kodu, na które możesz spojrzeć.

r1k0
źródło
Zaktualizowałem link. Projekt był hostowany na Google Code i jak wiemy został zamknięty. Link pochodzi z Github.
r1k0
8

Istnieje kilka różnych sposobów osiągnięcia tego, o co prosisz.

1.) Rozszerz klasę aplikacji i utwórz w niej instancję kontrolera i modeluj obiekty.

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

}

Następnie możesz wywołać singleton z niestandardowego obiektu aplikacji w dowolnym momencie:

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.) Możesz sprawić, aby kontroler po prostu utworzył pojedynczą instancję samego siebie:

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

Następnie możesz po prostu wywołać metodę create z dowolnego działania lub fragmentu, a utworzy nowy kontroler, jeśli jeszcze nie istnieje, w przeciwnym razie zwróci istniejący kontroler.

3.) Wreszcie, na Square stworzono ciekawy framework, który zapewnia wstrzyknięcie zależności w systemie Android. Nazywa się Sztylet . Nie będę się tutaj zastanawiał, jak go używać, ale jest bardzo sprytny, jeśli potrzebujesz tego rodzaju rzeczy.

Mam nadzieję, że podałem wystarczająco dużo szczegółów na temat tego, jak możesz zrobić to, na co masz nadzieję.

Dan Mikita
źródło
6

Spróbuj tak:

Utwórz udostępnioną klasę danych:

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



}

Zadeklarowano / zainicjowano wystąpienie klasy globalnie w tych klasach, w których chcesz ustawić / uzyskać dane (używając tego kodu przed onCreate()metodą): -

Globals sharedData = Globals.getInstance();

Ustaw dane:

sharedData.setValue("kundan");

Otrzymać dane:

String n = sharedData.getValue();
Kumar Kundan
źródło
4

Możesz stworzyć coś Global Classtakiego:

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

Następnie zdefiniuj to w manifeście:

<application
    android:name="com.example.globalvariable.GlobalClass" ....

Teraz możesz ustawić wartości zmiennej globalnej w następujący sposób:

final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
globalVariable.setName("Android Example context variable");

Możesz uzyskać następujące wartości:

final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
final String name  = globalVariable.getName();

Proszę znaleźć pełny przykład z tego bloga Global Variables

san88
źródło
3
// 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;
Mahasam
źródło
1
Dlaczego zamieszczasz dwie odpowiedzi na to samo pytanie? Możesz go edytować na jeden.
Kunu,
2

Poszukałem podobnej odpowiedzi, ale te podane tutaj nie odpowiadają moim potrzebom. Znajduję coś, co z mojego punktu widzenia jest tym, czego szukasz. Jedynym możliwym czarnym punktem jest kwestia bezpieczeństwa (a może nie), ponieważ nie wiem o bezpieczeństwie.

Sugeruję użycie interfejsu (nie musisz używać klasy z konstruktorem, więc ...), ponieważ musisz tylko stworzyć coś takiego:

public interface ActivityClass {

    public static final String MYSTRING_1 = "STRING";

    public static final int MYINT_1 = 1;

}

Następnie możesz uzyskać dostęp do wszystkich klas w swoich klasach, korzystając z następujących czynności:

int myInt = ActivityClass.MYINT_1;
String myString = ActivityClass.MYSTRING_1;
Alexandre
źródło
1

Technicznie nie odpowiada to na pytanie, ale zaleciłbym użycie bazy danych Room zamiast jakiejkolwiek zmiennej globalnej. https://developer.android.com/topic/libraries/architecture/room.html Nawet jeśli „tylko” potrzebujesz przechowywać zmienną globalną i nie jest to wielka sprawa, a co nie, ale korzystanie z bazy danych Room jest najbardziej eleganckie , natywny i dobrze wspierany sposób utrzymywania wartości przez cały cykl życia działania. Pomoże to uniknąć wielu problemów, zwłaszcza integralności danych. Rozumiem, że baza danych i zmienna globalna są różne, ale proszę używać Roomu ze względu na utrzymanie kodu, stabilność aplikacji i integralność danych.

sześciokąt
źródło
1

Użyj SharedPreferences do przechowywania i pobierania zmiennych globalnych.

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String userid = preferences.getString("userid", null);
Coen Damen
źródło
0

Jeśli to możliwe, powinieneś zadeklarować zmienne, które musisz zachować przy życiu, które nie zostały wyczyszczone przez Garbage Collector lub Unload by OS w pliku .so Aby to zrobić, musisz napisać kod w C / C ++ i skompilować do pliku .so lib i załaduj go do swojej MainActivity.

Tran Huu Phuoc
źródło
1
Kod macierzysty jest bolesnym sposobem przechowywania danych w pamięci RAM i nie robi tego lepiej niż staticzmienne Java .
Jerry101
Nie widzę sensu tego podejścia. Czy możesz wyjaśnić, w którym przypadku jest to dobry pomysł?
miva2
-1
import android.app.Application;

public class Globals extends Application
{
    private static Globals instance = null;
    private static int RecentCompaignID;
    private static int EmailClick;
    private static String LoginPassword;
    static String loginMemberID;
    private static String CompaignName = "";
    private static int listget=0;
    //MailingDetails
    private static String FromEmailadd="";
    private static String FromName="";
    private static String ReplyEmailAdd="";
    private static String CompaignSubject="";
    private static int TempId=0;
    private static int ListIds=0;

    private static String HTMLContent="";
    @Override
    public void onCreate() 
    {
        super.onCreate();
        instance = this;
    }

    public static Globals getInstance()
    {
        return instance;
    }

    public void setRecentCompaignID(int objRecentCompaignID)
    {
        RecentCompaignID = objRecentCompaignID;
    }

    public int getRecentCompaignID() 
    {
        return RecentCompaignID;
    }

    public void setLoginMemberID(String objloginMemberID) 
    {
        loginMemberID = objloginMemberID;
    }

    public String getLoginMemberID() 
    {
        return loginMemberID;
    }

    public void setLoginMemberPassword(String objLoginPassword)
    {
        LoginPassword = objLoginPassword;
    }

    public String getLoginMemberPassword()
    {
        return LoginPassword;
    }

    public void setEmailclick(int id)
    {
        EmailClick = id;
    }

    public int getEmailClick() 
    {
        return EmailClick;
    }
    public void setCompaignName(String objCompaignName)
    {
        CompaignName=objCompaignName;
    }
    public String getCompaignName()
    {
        return CompaignName;
    }
    public void setlistgetvalue(int objlistget)
    {
        listget=objlistget;
    }
    public int getlistvalue()
    {
        return listget;
    }
    public void setCompaignSubject(String objCompaignSubject)
    {
         CompaignSubject=objCompaignSubject;
    }
    public String getCompaignSubject()
    {
        return CompaignSubject;
    }
    public void setHTMLContent(String objHTMLContent)
    {
        HTMLContent=objHTMLContent;
    }
    public String getHTMLContent()
    {
        return HTMLContent;
    }
    public void setListIds(int objListIds)
    {
        ListIds=objListIds;
    }
    public int getListIds()
    {
        return ListIds;
    }
    public void setReplyEmailAdd(String objReplyEmailAdd)
    {
        ReplyEmailAdd=objReplyEmailAdd;
    }
    public String getReplyEmailAdd()
    {
        return ReplyEmailAdd;
    }
    public void setFromName(String objFromName)
    {
        FromName=objFromName;
    }
    public String getFromName()
    {
        return FromName;
    }
    public void setFromEmailadd(String objFromEmailadd)
    {
        FromEmailadd=objFromEmailadd;
    }
    public String getFromEmailadd()
    {
        return FromEmailadd;
    }
}
użytkownik2054528
źródło
-5

Łatwo!!!!

Te zmienne, do których chcesz uzyskać dostęp jako zmienna globalna, możesz zadeklarować jako zmienne statyczne. A teraz możesz uzyskać dostęp do tych zmiennych za pomocą

classname.variablename;

public class MyProperties {
private static MyProperties mInstance= null;

static int someValueIWantToKeep;

protected MyProperties(){}

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

}

MyProperites.someValueIWantToKeep;

Otóż ​​to! ;)

Dinesh Padwal
źródło
nie jestem pewien, dlaczego tak bardzo zostało to odrzucone; porównując z innymi odpowiedziami ocenionymi w sieci, widzę, że to poprawnie (iirc) używa synchronizedna statycznych, getInstance()podczas gdy inne nie. odpowiednio głosował.
user2297550