Jak deklarovat globální proměnné v Androidu?

hlasů
561

Jsem vytvořit aplikaci, která vyžaduje přihlášení. Vytvořil jsem hlavní a přihlašovací aktivitu.

V hlavní činnosti onCreatezpůsobu jsem přidal následující podmínku:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ...

    loadSettings();
    if(strSessionString == null)
    {
        login();
    }
    ...
}

onActivityResultZpůsob, který se provádí, když je formulář pro přihlášení končí vypadá takto:

@Override
public void onActivityResult(int requestCode,
                             int resultCode,
                             Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    switch(requestCode)
    {
        case(SHOW_SUBACTICITY_LOGIN):
        {
            if(resultCode == Activity.RESULT_OK)
            {

                strSessionString = data.getStringExtra(Login.SESSIONSTRING);
                connectionAvailable = true;
                strUsername = data.getStringExtra(Login.USERNAME);
            }
        }
    }

Problém je formulář pro přihlášení někdy objeví dvakrát (dále jen login()metoda se nazývá dvakrát) a také pokud je telefon klávesnice sklouzne přihlašovací formulář se znovu objeví a myslím, že problém je proměnná strSessionString.

Ví někdo, jak nastavit proměnnou globální, aby nedošlo k přihlašovací formulář se objeví poté, co uživatel již úspěšně autentizuje?

Položena 02/04/2009 v 02:54
zdroj uživatelem
V jiných jazycích...                            


17 odpovědí

hlasů
930

Napsal jsem tuto odpověď zpět do '09, kdy Android byl relativně nový, a tam bylo mnoho není dobře zavedené oblasti ve vývoji Android. Přidal jsem dlouhou dodatek v dolní části tohoto příspěvku, řeší nějakou kritiku, a podrobně popisuje filozofickou nesouhlas mám s použitím singletons spíše než subclassing aplikace. Přečtěte si ji na vlastní nebezpečí.

ORIGINAL ODPOVĚĎ:

Obecnější problém, který se kterými se setkávají, je, jak zachránit stát přes několik aktivit a všech částí aplikace. Statické proměnné (například, Singleton) je běžné Java způsob, jak toho dosáhnout. Zjistil jsem však, že více elegantní způsob, Android je spojit svůj stav s kontextem aplikace.

Jak víte, každá aktivita je také kontext, což je informace o jeho provádění životního prostředí v nejširším slova smyslu. Vaše žádost má také kontext, a Android zaručuje, že bude existovat jako jediná instance přes aplikaci.

Způsob, jak to udělat, je vytvořit si vlastní podtřídy android.app.Application a určit tuto třídu v tagu aplikace ve svém manifestu. Nyní Android automaticky vytvoří instanci této třídy a dát je k dispozici po celou dobu aplikace. K němu máte přístup z jakéhokoliv contextpoužití Context.getApplicationContext()metody ( Activityrovněž poskytuje způsob getApplication(), který má přesně stejný efekt). Následuje velmi zjednodušený příklad, s výhradami následovat:

class MyApp extends Application {

  private String myState;

  public String getState(){
    return myState;
  }
  public void setState(String s){
    myState = s;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyApp appState = ((MyApp)getApplicationContext());
    String state = appState.getState();
    ...
  }
}

To má v podstatě stejný účinek jako použití statické proměnné nebo Singleton, ale integruje velmi dobře do stávajícího Android rámce. Všimněte si, že to nebude fungovat v rámci procesů (měla vaše aplikace je jedním z mála těch, které má více procesů).

Něco si uvědomit z výše uvedeného příkladu; Předpokládám, že se místo toho udělal něco jako:

class MyApp extends Application {

  private String myState = /* complicated and slow initialization */;

  public String getState(){
    return myState;
  }
}

Nyní je tato pomalá inicializace (jako je bít disk, bít do sítě, blokování cokoliv, etc) bude provedena při každém Aplikace je instance! Můžete si myslet, no, to je jen jednou za proces a budu muset zaplatit náklady tak jako tak, je to tak? Například, jak je Dianne Hackborn zmiňuje níže, je zcela možné, aby váš proces musí být vytvořena -již- zvládnout akci na pozadí vysílání. Pokud vaše zpracování vysílání nemá potřebu tomto stavu jste potenciálně právě udělal celou řadu složitých a pomalých operací pro nic za nic. Lazy instance je název hry zde. Níže je poněkud složitější způsob použití aplikace, která dává větší smysl pro něco jiného než ty nejjednodušší použití:

class MyApp extends Application {

  private MyStateManager myStateManager = new MyStateManager();

  public MyStateManager getStateManager(){
    return myStateManager ;
  }
}

class MyStateManager {

  MyStateManager() {
    /* this should be fast */
  }

  String getState() {
    /* if necessary, perform blocking calls here */
    /* make sure to deal with any multithreading/synchronicity issues */

    ...

    return state;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
    String state = stateManager.getState();
    ...
  }
}

I když jsem raději Application subclassing použitím singletons zde jako elegantnější řešení, já bych raději používají vývojáři singletons-li opravdu nezbytné v průběhu nemyslí vůbec na důsledky výkonu a multithreading o sdružování stav s podtřídy aplikace.

Poznámka 1: Také jako anticafe poznamenal, aby se správně uvázat vaši žádost přepsání aplikace je nutný tag v souboru manifestu. Opět viz Android dokumenty pro více informací. Příklad:

<application
     android:name="my.application.MyApp" 
     android:icon="..."
     android:label="...">
</application>

Poznámka 2: user608578 ptá níže, jak to funguje s řízením nativní objekt životních cyklů. Nejsem až do rychlosti na použití nativního kódu s operačním systémem Android v nejmenším, a nejsem způsobilý odpovědět, jak by to v interakci se svým řešením. Pokud někdo má odpověď na to, jsem ochoten jim úvěr a dal informace v tomto příspěvku pro maximální viditelnost.

DODATEK:

Jak je již uvedeno někteří lidé, to není řešení pro přetrvávající stav, něco, co bych snad měl být kladen větší důraz v původní odpovědi. Tedy to není chtěl být řešením pro ukládání uživatele nebo jiné informace, které by mělo být přetrvával přes aplikační životů. Tudíž se domnívám, většina kritiky níže se týkají žádostí byl zabit kdykoliv, atd ..., diskutabilní, protože vše, co kdy bylo třeba trval na disku by neměl být uložen přes podtřídy aplikace. To je chtěl být řešením pro ukládání dočasných, snadno znovu creatable stav aplikace (zda je uživatel přihlášen, například) a složky, které jsou jediné instance (žádost správce sítě například) ( NOT Singleton!) V přírodě.

Dayerman byl tak laskav poukázat na zajímavý rozhovor s Reto Meier a Dianne Hackborn , ve kterém je použití aplikačních podtřídy odrazuje ve prospěch Singleton vzorů. Somatik také poukázal na něco tohoto druhu dříve, i když jsem to neviděl v té době. Kvůli Reto a role Dianne je v udržování platformu Android, nemohu v dobré víře, doporučujeme ignorovat jejich rady. Co říkají, pokračuje. Já bych nesouhlasí s názory vyjádřené s ohledem na preferování Singleton přes aplikace podtřídy. Podle mého nesouhlasu budu s využitím koncepcí nejlépe vysvětlit v tomto StackExchange vysvětlení návrhového vzoru Singleton , takže nemám definovat pojmy v této odpovědi. I velmi povzbudit skluzem na odkaz před pokračováním. Bod po bodu:

Dianne říká: „Není žádný důvod, aby podtřídy z aplikace. To není jiný, než dělat singleton ...“ Toto první tvrzení je nesprávné. Existují dva hlavní důvody pro toto. 1) Třída Aplikace poskytuje lepší doživotní záruku vývojář aplikace; je zaručeno, že životnost aplikace. Singleton není výslovně vázána na dobu trvání aplikace (i když je účinně). To může být non-záležitost pro průměrného vývojáře aplikací, ale já bych tvrdit, to je přesně ten typ smlouvy Android API je třeba nabízet, a to poskytuje mnohem větší flexibilitu systému Android i tím, že minimalizuje životnost přidružené data. 2) Třída Aplikace poskytuje vývojář aplikace s jedním držákem například pro stav, který je velmi odlišný od držáku Singleton státu. Pro seznam rozdílů, viz vysvětlení odkaz Singleton výše.

Dianne pokračuje: „... jen pravděpodobné, že bude něco, co litovat v budoucnu, jak si najít svůj objekt Application stát tento velký zamotaný nepořádek z toho, co by mělo být nezávislé logika aplikace.“ To rozhodně není správné, ale to není důvodem pro volbu Singleton přes aplikace podtřídy. Žádný z argumentů Diane poskytují důvod, že pomocí Singleton je lepší než podtřídy aplikace, vše, co se snaží prokázat, že pomocí Singleton není o nic horší než podtřídy aplikací, což je podle mého názoru falešný.

Ona pokračuje: „A to vede více přirozeně, jak byste měli být řízení těchto věcí. - inicializace je na vyžádání“ Toto ignoruje skutečnost, že neexistuje žádný důvod, proč nemůžete inicializovat na požádání s použitím podtřídy aplikace stejně. Opět není žádný rozdíl.

Dianne končí s „Rámec sám má tuny a tuny singletons pro všechny malé sdílených dat němu zůstávají pro aplikace, jako je například cache zatížených zdrojů, bazény objektů apod Funguje to skvěle.“ Netvrdím, že používání singletons nemůže fungovat dobře, nebo nejsou legitimní alternativou. Tvrdím, že singletons neposkytují tak silnou smlouvu se systémem Android as pomocí podtřídy aplikace, a dále, že používání singletons obecně poukazuje na nepružné konstrukce, která není snadno modifikovat, a vede k mnoha problémům dolů na silnici. IMHO, silná smlouva o Android API nabízí vývojáře aplikací je jedním z nejzajímavějších a potěšující aspekty programování s operačním systémem Android, a pomáhal vést k přijetí časného vývojáře, který jel na platformě Android k úspěchu to má dnes. Navrhovat pomocí singletons implicitně odklon od silné smlouvy o API, a podle mého názoru, oslabuje Android rámec.

Dianne okomentoval níže stejně, za zmínku další nevýhodu k používání aplikací podtřídy, které mohou podporovat nebo snazší psát méně kódu výkonu. Toto je velmi pravdivé, a jsem upravil tuto odpověď zdůraznit, že je důležité s ohledem na perf tady, a brát správný přístup, pokud používáte aplikace subclassing. Jako Dianne uvádí, že je důležité mít na paměti, že vaše třída Aplikace bude vytvořena pokaždé, když proces je načten (může být vícekrát najednou, pokud aplikace běží v několika procesech!), I když je tento proces byl načten jen na pozadí vysílání událost. Proto je důležité používat třídu Application spíše jako úložiště pro ukazatelů ke sdíleným složkám vaší žádosti, spíše než jako místo dělat jakékoli zpracování!

Nechám tě s následujícího seznamu stinné stránky singletons, jako odcizené od dřívějšího StackExchange odkazu:

  • Nemožnost používat abstraktní nebo rozhraní třídy;
  • Neschopnost podtřídy;
  • Spojka celé aplikace (obtížné změnit);
  • Obtížné pro testování (nelze falešné / mock v jednotkové testy);
  • Obtížné paralelizovat v případě měnitelného stavu (vyžaduje rozsáhlé zamykání);

a přidat svůj vlastní:

  • Nejasné a nezvládnutelný smlouva životnost nevhodný pro Android (nebo většina ostatních) rozvoj;
Odpovězeno 02/04/2009 v 05:34
zdroj uživatelem

hlasů
151

Vytvoření této podtřídy

public class MyApp extends Application {
  String foo;
}

V AndroidManifest.xml přidat androida: jméno

Příklad

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">
Odpovězeno 26/07/2010 v 21:31
zdroj uživatelem

hlasů
136

Navržená podle Soonil způsob, jak udržet stav pro aplikaci je dobrá, ale má jednu slabinu - existují případy, kdy OS zabije celý proces aplikace. Zde je dokumentace na to - procesů a životní cykly .

Vezměme si případ - vaše aplikace přejde do pozadí, protože někdo vám volá (Phone aplikace je v popředí nyní). V tomto případě && za určitých dalších podmínek (zkontrolujte výše uvedený odkaz na to, co by mohlo být), operační systém může zabít proces podávání žádosti, včetně Applicationnapříklad podtřídy. V důsledku toho dojde ke ztrátě stavu. Když se později vrátit do aplikace, pak OS obnoví svou činnost stack a Applicationpodtřídy instance však myStatebude pole null.

Pokud vím, jediný způsob, jak zaručit bezpečnost státu je použít nějaký druh přetrvávající stav, například s použitím vlastní souboru aplikace nebo SharedPrefernces(to nakonec používá vlastní souboru aplikace ve vnitřním souborovém systému).

Odpovězeno 09/01/2011 v 22:49
zdroj uživatelem

hlasů
25

Pouze poznámka ..

přidat:

android:name=".Globals"

nebo co si pojmenovali podtřídy ke stávající <application> značky. Pořád jsem se snaží přidat další <application>záznam do manifestu a dostane výjimku.

Odpovězeno 13/04/2011 v 22:29
zdroj uživatelem

hlasů
13

Co se týká zajištění sběru nativní paměti s takovými globálními strukturami?

Aktivity mají onPause/onDestroy()metodu, která se nazývá po zničení, ale třída Application nemá ekvivalent. Jakým mechanismem se doporučuje, aby zajistily, že globální struktury (zejména ty, které obsahují zmínky nativní paměti) jsou odpadky shromažďují vhodným způsobem, kdy je přihláška buď zabiti, nebo stack úkol dát do pozadí?

Odpovězeno 25/02/2011 v 19:32
zdroj uživatelem

hlasů
13

Nemohl jsem najít, jak určit značku aplikace buď, ale po hodně Googling, bylo zřejmé, ze zjevných dokumenty souborů: Použití android: jméno, vedle ikony z prodlení a etiketa v aplikačním sloky.

android: name úplný název podtřídy aplikace realizované pro danou aplikaci. Při spuštění procesu aplikace, tato třída je vytvořena před některým součástí aplikace.

Podtřída je volitelný; většinu aplikací nebude potřebovat. V nepřítomnosti podtřídy, Android používá instanci třídy základní aplikace.

Odpovězeno 14/01/2010 v 06:26
zdroj uživatelem

hlasů
5

Jen je potřeba definovat název aplikace podobně, pod níž bude fungovat:

<application
  android:name="ApplicationName" android:icon="@drawable/icon">
</application>
Odpovězeno 07/01/2011 v 06:57
zdroj uživatelem

hlasů
4

Jako by tam bylo diskutováno výše OS mohl zabít aplikaci bez jakéhokoli oznámení (není žádná událost onDestroy), takže není žádný způsob, jak zachránit tyto globální proměnné.

SharedPreferences by mohlo být řešením KROMĚ máte komplexních strukturovaných proměnných (v mém případě jsem měl celočíselné pole pro ukládání ID, že uživatel již zpracovány). Problém s SharedPreferences je, že je těžké pro ukládání a načítání tyto struktury pokaždé, když jsou hodnoty potřebné.

V mém případě jsem měl služba na pozadí, takže jsem mohl přesunout tento proměnných tam, a protože tato služba má onDestroy událost, mohl bych snadno uložit tyto hodnoty.

Odpovězeno 02/11/2012 v 09:53
zdroj uživatelem

hlasů
4

Jsou-li některé proměnné uloženy v databázi SQLite a je nutné je použít ve většině aktivit ve vaší aplikaci. pak Application možná nejlepší způsob, jak toho dosáhnout. Dotaz proměnné z databáze při spuštění aplikace a uložit je na poli. Pak můžete použít tyto proměnné ve svých aktivitách.

Takže najít správnou cestu, a není nejlepší způsob.

Odpovězeno 20/04/2011 v 08:32
zdroj uživatelem

hlasů
3

Můžete mít statickou pole pro uložení tohoto druhu stavu. Nebo dát ji do zdrojového svazku a obnovit odtamtud na onCreate (Bundle savedInstanceState). Jen ujistěte se, že zcela pochopit aplikace pro Android se podařilo životní cyklus (např proč login () je volána na klávesnici změně orientace).

Odpovězeno 02/04/2009 v 03:19
zdroj uživatelem

hlasů
2

DO NOT Použijte jinou <application>značku ve zjevném file.Just udělat jednu změnu ve stávající <application>značce, přidejte tento řádek android:name=".ApplicationName"kde, ApplicationNamebude název vaší podtřídy (použití k ukládání globální), že jste se chystá vytvořit.

takže nakonec vaše jediná <application> značka v souboru manifestu by měl vypadat takto: -

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.NoActionBar"
        android:name=".ApplicationName"
        >
Odpovězeno 22/06/2015 v 11:20
zdroj uživatelem

hlasů
1

To lze provést pomocí dvou přístupů:

  1. Používání třídy Application
  2. Používání sdílených předvoleb

  3. Používání třídy Application

Příklad:

class SessionManager extends Application{

  String sessionKey;

  setSessionKey(String key){
    this.sessionKey=key;
  }

  String getSessisonKey(){
    return this.sessionKey;
  }
}

Můžete použít výše třídy implementovat přihlášení v MainActivity jak je uvedeno níže. Kód bude vypadat nějak takto:

@override 
public void onCreate (Bundle savedInstanceState){
  // you will this key when first time login is successful.
  SessionManager session= (SessionManager)getApplicationContext();
  String key=getSessisonKey.getKey();
  //Use this key to identify whether session is alive or not.
}

Tato metoda bude pracovat pro dočasné uskladnění. Ty opravdu nemají žádnou představu, kdy operační systém je zabije žádosti, z důvodu nedostatku paměti. Když aplikace je v pozadí a uživatel je procházení jiné aplikace, která vyžaduje více paměti ke spuštění, pak se vaše žádost bude zabit, protože operační systém dané vyšší priorita popředí procesů než pozadí. Z tohoto důvodu aplikace objekt bude null, než uživatel odhlásí. Z tohoto důvodu pro to doporučuji využít druhý způsob výše uvedených.

  1. Pomocí sdílených předvoleb.

    String MYPREF="com.your.application.session"
    
    SharedPreferences pref= context.getSharedPreferences(MyPREF,MODE_PRIVATE);
    
    //Insert key as below:
    
    Editot editor= pref.edit();
    
    editor.putString("key","value");
    
    editor.commit();
    
    //Get key as below.
    
    SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
    
    String key= getResources().getString("key");
    
Odpovězeno 19/12/2015 v 13:03
zdroj uživatelem

hlasů
0

Mohli byste vytvořit třídu, která rozšiřuje Applicationtřídu a pak deklarovat svou proměnné jako pole této třídy a poskytuje metody getter za to.

public class MyApplication extends Application {
    private String str = "My String";

    synchronized public String getMyString {
        return str;
    }
}

A pak pro přístup k této proměnné ve své činnosti, použijte toto:

MyApplication application = (MyApplication) getApplication();
String myVar = application.getMyString();
Odpovězeno 28/11/2015 v 13:05
zdroj uživatelem

hlasů
0

Přístup podtříd byl také používán v rámci Baracus. Z mého pohledu subclassing Aplikace byla určena pro práci s celou dobu životního cyklu Android; To je to, co některý Application Container dělá. Místo toho, aby globals té doby jsem zaregistrovat fazole těchto okolností by nechal soupisky vstřikuje do každé třídy zvládnutelné kontextem. Každý injekčně instance bean ve skutečnosti je ojedinělým.

Viz tento příklad Podrobnosti

Proč ruční práci, pokud můžete mít mnohem víc?

Odpovězeno 11/11/2014 v 13:01
zdroj uživatelem

hlasů
0

Na aktivity výsledek je volána před k životopisu. Takže pohybovat přihlášení zkontrolovat na životopis a vaše druhá přihlášení lze blokovat, jakmile secomd aktivita vrátila pozitivní výsledek. On životopisu se nazývá pokaždé, takže není obavy z ní není volána poprvé.

Odpovězeno 11/10/2014 v 08:36
zdroj uživatelem

hlasů
0
class GlobaleVariableDemo extends Application {

    private String myGlobalState;

    public String getGlobalState(){
     return myGlobalState;
    }
    public void setGlobalState(String s){
     myGlobalState = s;
    }
}

class Demo extends Activity {

@Override
public void onCreate(Bundle b){
    ...
    GlobaleVariableDemo appState = ((GlobaleVariableDemo)getApplicationContext());
    String state = appState.getGlobalState();
    ...
    }
}
Odpovězeno 17/07/2014 v 11:31
zdroj uživatelem

hlasů
0

můžete použít záměry, SQLite, nebo sdílené předvolby. Když přijde na úložiště médií, jako jsou dokumenty, fotografie a videa, můžete místo toho vytvořit nové soubory.

Odpovězeno 16/07/2013 v 02:35
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more