Aplikace se nemusí vždy skládat z jedné obrazovky. Vytvořili jsme například velmi užitečný program a uživatel chce vědět, kdo je autor. Klikne na tlačítko „O programu“ a dostane se na novou obrazovku, kde jsou užitečné informace o verzi programu, autorovi, adrese webu, kolik má autor koček atd. Obrazovku aktivity si představte jako webovou stránku s odkazem na jinou stránku. Pokud se podíváte na kód v souboru MainActivity.java z předchozích lekcí uvidíte, že naše třída Hlavní aktivita platí také pro Aktivita(nebo jeho dědiců) nebo přesněji zděděných po něm.
Veřejná třída MainActivity rozšiřuje AppCompatActivity
Jak asi tušíte, měli bychom vytvořit novou třídu, která může vypadat takto Hlavní aktivita a pak se na to nějak přepnout při stisku tlačítka.
Pro experiment vezmeme program z první lekce a použijeme tlačítko pro experimenty (nebo vytvoříme nový projekt jedním tlačítkem na obrazovce). Dále pojďme tvořit nový formulář zobrazit užitečné informace... Ukažme například uživateli, co kočka dělá, když chodí doleva a doprava. Souhlasíte, toto je velmi důležitá informace, která poskytuje vodítko k vesmíru.
Novou aktivitu vytvoříme ručně, přestože má studio hotové šablony. Není to ale nic složitého a pro lepší pochopení je užitečné dělat vše ručně.
Pojďme vytvořit nový soubor značek XML activity_about.xml ve složce rozlišení / rozložení... Klikněte pravým tlačítkem na složku rozložení a vybrat si z kontextová nabídka Nový | Soubor prostředku rozložení... Zobrazí se dialogové okno. Do prvního pole zadejte název souboru činnost_o... Ve druhém musíte zadat kořenový prvek. Ve výchozím nastavení je ConstraintLayout... Vymažte text a zadejte ScrollView... Zadání několika znaků stačí, aby studio navrhlo hotové možnosti, můžete okamžitě stisknout Enter, aniž byste čekali na úplné zadání slova:
Dostaneme odpovídající polotovar, do kterého prvek vložíme. TextView.
Informace budou načteny ze zdrojů, konkrétně z řetězcového zdroje o_textu... Nyní je zvýrazněn červeně, což signalizuje nedostatek informací. Mohl bys stisknout Alt + Enter a zadejte text do dialogového okna. Ale pro náš příklad tato metoda nebude fungovat, protože náš text bude víceřádkový s použitím řídicích znaků. Tak na to pojďme jinak. Otevřeme soubor res / hodnoty / strings.xml a ručně zadejte následující text:
Použili jsme nejjednodušší HTML značky pro formátování textu jako , , ... Pro náš příklad stačí tučně zvýraznit slova, která odkazují na kočku a směr pohybu. K překladu textu do nový řádek používat symboly \ n... Pojďme přidat další zdroj řetězce pro název nové obrazovky:
Přišli jsme na označení. Dále musíte vytvořit třídu pro okno AboutActivity.java... Vyberte si z nabídky Soubor | Nový | Třída Java a vyplňte požadovaná pole. Nejprve stačí uvést pouze jméno. Pak se zabývají dalšími obory.
Vezmeme si prázdno.
Třída je nyní téměř prázdná. Pojďme přidat kód ručně. Třída musí dědit z abstraktní třídy Aktivita nebo jako jeho příbuzní FragmentActivity, AppCompatActivity atd. Přidali jsme rozšiřuje Aktivitu... Třída aktivity musí mít metodu onCreate ()... Umístíme kurzor myši do třídy a vybereme z nabídky Kód | Přepsat metody(Ctrl + O). V dialogovém okně hledáme požadovanou třídu, pro kterou můžete zadat první znaky na klávesnici rychlé hledání... Ve vytvořené metodě je třeba metodu zavolat setContentView () který načte připravené označení na obrazovku. Tuto možnost získáme.
Balíček ru.alexanderklimov.helloworld; importovat android.app.Activity; importovat android.os.Bundle; / ** * Vytvořil Alexander Klimov dne 01.12.2014. * / public class AboutActivity rozšiřuje aktivitu (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_about);))
Nyní začíná to nejdůležitější. Naším úkolem je přejít na novou obrazovku po kliknutí na tlačítko na první obrazovce. Vraťte se do třídy Hlavní aktivita... Pojďme napsat obslužný program kliknutí na tlačítko:
Public void onClick (View view) (Intent intent = nový Intent (MainActivity.this, AboutActivity.class); startActivity (intent);)
Zde jsem použil metodu zpracování kliknutí na tlačítka, kterou jsem popsal v lekci.
Chcete-li spustit novou obrazovku, musíte vytvořit instanci třídy Úmysl a zadejte aktuální třídu v prvním parametru a třídu pro přechod ve druhém parametru, máme toto O Aktivitě... Poté je zavolána metoda startActivity () který spustí novou obrazovku.
Pokud se nyní pokusíte otestovat fungování aplikace v emulátoru, zobrazí se chybová zpráva. co jsme udělali špatně? Chybí nám jeden důležitý krok. Musíte zaregistrovat nový Aktivita v manifestu AndroidManifest.xml... Najděte tento soubor ve svém projektu a dvakrát na něj klikněte. Otevře se okno pro úpravu souboru. Přidat novou značku
Zdroj řetězce se tedy hodil about_title... Spusťte aplikaci, klikněte na tlačítko a otevřete okno O programu... Naučili jsme se tedy, jak vytvořit nové okno a vyvolat jej kliknutím na tlačítko. A máme k dispozici megapohodlný program - nyní bude vždy po ruce nápověda, co kočka dělá, když jde doleva.
Ještě jednou upozorňuji na skutečnost, že druhá vytvořená třída aktivity musí dědit od třídy Aktivita nebo jemu podobný ( Aktivita seznamu a další), mít soubor značek XML (je-li vyžadován) a musí být zapsán v manifestu.
Po zavolání metody startActivity () začne nová aktivita (v tomto případě O Aktivitě), stane se viditelným a přesune se na vrchol zásobníku obsahujícího běžící komponenty. Při volání metody Dokončit () z nové aktivity (nebo když stisknete klávesu tvrdého návratu) bude uzavřena a odstraněna ze zásobníku. Vývojář může také přejít na předchozí (nebo jakoukoli jinou) aktivitu pomocí stejné metody. startActivity ().
Jak vytvořit třetí obrazovku - způsob pro líné
Programátoři, stejně jako kočky, jsou líná stvoření. Vždy si pamatujte, že pro aktivitu je třeba vytvořit označení a třídu, ze které dědí Aktivita, a poté nezapomeňte třídu zaregistrovat do manifestu - dobře nafig.
V tomto případě vyberte z nabídky Soubor | Nový | Aktivita | Základní činnost(nebo jinou šablonu). Dále se objeví známé okno pro vytvoření nové aktivity. Vyplníme povinná pole.
Klikněte na tlačítko Dokončit a aktivita bude připravena. Chcete-li to ověřit, otevřete soubor manifestu a vyhledejte nový záznam. Nemluvím o souborech tříd a značek, ty samy se před vámi objeví.
Sami si přidejte nové tlačítko na obrazovku hlavní aktivity a napište kód pro přechod na vytvořenou aktivitu.
Nejprve bych vám doporučil ručně vytvořit všechny potřebné komponenty pro novou aktivitu, abyste pochopili vztah mezi třídou, označením a manifestem. A když se vám to dostane do rukou, můžete si práci urychlit pomocí Průvodce tvorbou aktivity.
Přenos dat mezi aktivitami
Použili jsme nejjednodušší příklad k vyvolání obrazovky další aktivity. Někdy je potřeba nejen zavolat novou obrazovku, ale také na ni přenést data. Například uživatelské jméno. V tomto případě musíte použít speciální oblast extraData které třída má Úmysl.
Kraj extraData je seznam párů klíč / hodnota který je předán spolu se záměrem. Řetězce se používají jako klíče a pro hodnoty můžete použít jakékoli primitivní datové typy, pole primitiv, objekty tříd Svazek atd.
Chcete-li přenést data do jiné aktivity, použijte metodu putExtra ():
Intent.putExtra ("Klíč", "Hodnota");
Přijímací aktivita by měla volat nějakou vhodnou metodu: getIntExtra (), getStringExtra () atd.:
Počet int = getIntent (). GetIntExtra ("název", 0);
Zopakujme předchozí příklad. Máme za sebou již tři aktivity. První aktivita bude mít dvě textová pole a tlačítko. Vzhled může být následující:
Druhá činnost Druhá aktivita nainstalujte prvek TextView, ve kterém zobrazíme text přijatý z první aktivity. Pojďme napsat následující kód pro metodu onCreate () při druhé aktivitě.
@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_second); String user = "Live"; String gift = "díra v koblihu"; TextView infoTextView = (TextView) findViewById R. id.textViewInfo); infoTextView.setText (uživatel + ", dostali jste" + dárek);)
Pokud nyní spustíme program a pouze vyvoláme druhé okno, jak je popsáno v první části článku, uvidíme výchozí označení Zhivotnoe, dostal jsi díru na koblihu... Souhlas, je docela škoda takové zprávy dostávat.
Opravujeme situaci. Přidejte kód pro první aktivitu:
Public void onClick (Zobrazit zobrazení) (EditText userEditText = (EditText) findViewById (R.id.editTextUser); EditText giftEditText = (EditText) findViewById (R.id.editTextGift); Intent intent = nová třída Intent (SecondActivity); / / vloží text z prvního textového pole do klíče uživatelského jména intent.putExtra („uživatelské jméno“, userEditText.getText (). toString ()); // vloží text z druhého textového pole do dárkového klíče intent.putExtra ( "gift ", giftEditText.getText (). toString ()); startActivity (záměr);)
Předmět jsme umístili do speciálního kontejneru Úmysl dva klíče s hodnotami převzatými z textových polí. Když uživatel zadá data do textových polí, přejde do tohoto kontejneru a bude převeden do druhé aktivity.
Druhá aktivita by měla být připravena přijímat teplé zprávy následovně (tučně).
// Výchozí hodnoty String user = "Live"; String gift = "díra na koblihu"; uživatel = getIntent (). getExtras (). getString ("uživatelské jméno"); dárek = getIntent (). getExtras (). getString ("dárek"); TextView infoTextView = (TextView) findViewById (R.id.textViewInfo); infoTextView.setText (uživatel + ", dostali jste" + dárek);
Nyní zpráva nevypadá tak urážlivě, ale pro některé lidi dokonce příjemně. Ve složitých příkladech je žádoucí přidat validaci při zpracování dat. Jsou situace, kdy zahájíte druhou aktivitu s prázdnými daty jako nula což by mohlo způsobit pád aplikace.
V našem případě víme, že čekáme na hodnotu řetězce, takže kód lze přepsat takto:
Záměr záměr = getIntent (); user = intent.getStringExtra ("uživatelské jméno");
Uživatel = getIntent (). GetStringExtra ("uživatelské jméno");
Program má nevýhodu - není jasné, od koho dostáváme pozdravy. Žádná dobře vychovaná opice nepřijme dar od anonymního zdroje. Takže jako domácí úkol přidejte další textové pole pro zadání jména uživatele, který zprávu posílá.
Google doporučuje používat pro klíče následující formát: název vašeho balíčku jako předponu a za ním samotný klíč. V tomto případě si můžete být jisti, že klíč je jedinečný při interakci s jinými aplikacemi. Něco takového:
Veřejný konečný statický řetězec USER = "ru.alexanderklimov.myapp.USER";
Kdo zarámoval kočku Vasku - vracíme výsledek
Ne vždy stačí pouze předat data jiné činnosti. Někdy chcete získat informace zpět z jiné aktivity, když ji zavřete. Pokud jsme dříve použili metodu startActivity (záměr), pak existuje příbuzná metoda startActivityForResult (záměr záměru, int kód požadavku)... Rozdíl mezi metodami je extra parametr Požadovat kód... Je to v podstatě jen celé číslo, které si můžete vytvořit sami. Je potřeba, aby bylo možné rozlišit, od koho výsledek přišel. Řekněme, že máte pět dalších obrazovek a přiřadíte jim hodnoty od 1 do 5 a z tohoto kódu můžete určit, čí výsledek potřebujete zpracovat. Můžete použít hodnotu -1, pak to bude stejné jako při volání metody startActivity (), tj. nedosáhneme žádného výsledku.
Pokud použijete metodu startActivityForResult (), pak musíte přepsat metodu v kódu, abyste získali výsledek onActivityResult () a zpracovat výsledek. Zmatený? Vezměme si příklad.
Předpokládejme, že jste detektiv. Objevily se informace, že v restauraci byly ze stolu vlivné osoby odcizeny dva kusy klobásy a další produkty. Podezření padlo na tři podezřelé - vránu, zasraného pejska a kočku Vasku.
Jeden z návštěvníků poskytl sérii fotografií ze svého poníka iPhone:
Existuje také svědectví dalšího svědka: A Vaska poslouchá, ale jí.
Vytvořte nový projekt Sherlock se dvěma aktivitami. Na první obrazovce bude tlačítko pro přepnutí na druhou obrazovku a textový popisek, ve kterém bude zobrazeno jméno zloděje.
Druhá obrazovka bude mít skupinu přepínačů:
Protože budeme očekávat odpověď od druhé obrazovky, musíme metodu použít startActivityForResult () na první obrazovce, ve které předáváme proměnnou CHOOSE_THIEF jako parametr Požadovat kód.
Statické konečné private int CHOOSE_THIEF = 0; public void onClick (View v) (Záměr questionIntent = nový záměr (MainActivity.this, ChooseActivity.class); startActivityForResult (questionIntent, CHOOSE_THIEF);)
Podívejte se na kód. Po kliknutí na tlačítko začneme pracovat s druhou obrazovkou Vyberte Aktivita a spusťte druhou obrazovku a počkejte na výsledek.
Přejděte na druhou obrazovku a napište kód pro druhou aktivitu.
Veřejné finále statické String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick (View v) (Intent answerIntent = new Intent (); switch (v.getId ()) (case R.id.radioDog: answerIntent.putExtra (THIEF, "Fucking doggie"); break; case R.id .radioCrow: answerIntent.putExtra (THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra (THIEF, "Kůň Převalského"); break; default: break;) setResult (RESULT_OK, answerIntent); dokončit ();)
Všechno je zde jednoduché, když detektiv vybere jméno zločince, pak prostřednictvím metody putExtra () předáme jméno klíče a jeho hodnotu.
Pro usnadnění po výběru ihned zavřeme druhé okno a před zavřením předáme hodnotu RESULT_OK aby bylo jasné, že volba byla učiněna. Pokud uživatel zavře obrazovku pomocí tlačítka Zpět, hodnota bude předána RESULT_CANCELED.
Metoda setResult () přebírá dva parametry: výsledný kód a samotný výsledek, reprezentovaný jako záměr. Výsledný kód vám říká, jakým výsledkem aktivita skončila, zpravidla to je buď Aktivita.RESULT_OK nebo Aktivita.RESULT_CANCELED... V některých případech možná budete muset použít svůj vlastní návratový kód ke zpracování variant specifických pro vaši aplikaci. Metoda setResult () podporuje libovolnou celočíselnou hodnotu.
Pokud budete data předávat explicitně přes tlačítko, pak by bylo hezké přidat metodu Dokončit () zavřít druhou činnost jako nepotřebnou. Pokud k přechodu dojde pomocí tlačítka Zpět, není to nutné.
Pokud byla činnost uzavřena uživatelem při stisknutí hardwarového tlačítka návratu, nebo pokud metoda Dokončit () byla volána před metodou setResult (), výsledný kód bude nastaven na RESULT_CANCELED a vrácený záměr zobrazí hodnotu nula.
Vracíme se na první obrazovku. První obrazovka čeká na odpověď z druhé obrazovky, takže je potřeba přidat metodu do kódu onActivityResult ().
@Override protected void onActivityResult (int requestCode, int resultCode, Intent data) (super.onActivityResult (requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById (R.id.textViewInfo); if (requestCode == CHOOSE_THIEF) ( if (resultCode == RESULT_OK) (String thiefname = data.getStringExtra (ChooseActivity.THIEF); infoTextView.setText (název zloděje);) else (infoTextView.setText (""); // smazat text)))
Metoda očekává příchozí data s kódem CHOOSE_THIEF a pokud taková data dorazí, extrahuje hodnotu z klíče ZvolteActivity.THIEF pomocí metody getStringExtra... Výslednou hodnotu vypíšeme v TextView(proměnná infoTextView). Pokud jsme se vrátili na obrazovku přes tlačítko Zpět, pak text jednoduše vymažeme.
Když je podřízená aktivita uzavřena uvnitř nadřazené komponenty, spustí se obslužná rutina onActivityResult ()... Psovod onActivityResult () má několik parametrů.
- Požadovat kód. Kód, který byl použit ke spuštění aktivity vracející výsledek
- Kód výsledku. Kód výsledku nastavený podřízenou aktivitou, který označuje, jak aktivita skončila. Může to být libovolná celočíselná hodnota, ale obvykle buď Aktivita.RESULT_OK nebo Aktivita.RESULT_CANCELED
- Data. Záměr použitý k zabalení vrácených dat. V závislosti na účelu podřízené aktivity může zahrnovat cestu URI představující vybranou část obsahu. Alternativně (nebo navíc) může podřízená aktivita vracet informace jako jednoduché hodnoty zabalené do parametru intent doplňky
Pokud byla podřízená aktivita neočekávaně ukončena nebo pokud nebyl před jejím uzavřením zadán žádný kód výsledku, stane se tento parametr Aktivita.RESULT_CANCELED.
Spustíme projekt, klikneme na tlačítko a přejdeme na druhou obrazovku. Tam si vybereme jednu z možností. Pokud vyberete vránu, obrazovka se zavře a na první obrazovce se zobrazí jméno viníka. Pokud vyberete psa, zobrazí se jeho jméno.
Mimochodem, pokud vyberete kočku, její jméno se nezobrazí! Podívejte se na to a přesvědčte se sami. Budete se ptát proč? Základní Watson! Pachatel nevzal v úvahu jeden důležitý detail. Restaurace byla monitorována videokamerami a na videu bylo vidět, kdo vlastně ukradl klobásu a zarámoval kočku. Vasko, vydrž!
P.S. Pokud se zpočátku něco zdálo nepochopitelné, pak se praxí mnohé vyjasní. Přenos dat mezi obrazovkami je v aplikacích běžný a příklad budete studovat znovu a znovu.
P.P.S. Nejlepší ryba je klobása. S vědomím této slabosti nebylo těžké kočku zarámovat.
Použití filtrů
V článku jsem ukázal běžný způsob, jak přejít na jinou činnost, když v metodě startActivity () je uvedena aktuální třída a třída pro přechod. Mimochodem, třída aktivity nemusí být součástí vaší aplikace. Pokud znáte název třídy z jiné aplikace, můžete se na ni přepnout. Na jinou činnost ale můžete jít jiným způsobem.
V praxi je to méně obvyklé, ale může to být užitečné. Řekněme, že už máte druhou aktivitu. Přidejte do manifestu speciální filtr:
A druhou aktivitu spustíme kliknutím na tlačítko tímto způsobem.
Public void onClick (View view) (startActivity (nový Intent ("ru.alexanderklimov.testapplication.SecondActivity"));)
Nahraďte dlouhý řetězec konstantou.
Veřejné statické finále Řetězec ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick (zobrazení zobrazení) (startActivity (nový záměr (ACTION_SECOND_ACTIVITY));)
Tak co jsme udělali. Pro druhou aktivitu jsme přidali filtr a zadali název pro akce v atributu android: jméno... Pro usnadnění jsem do něj vložil celý název aktivity s názvem balíčku. Konstruktor třídy Úmysl má několik přetížených verzí. V jedné verzi můžete zadat řetězec pro akci. Naznačili jsme naši vytvořenou akci, která je registrována ve druhé aktivitě. Systém během provozu prohlíží manifesty všech nainstalovaných aplikací. Při hledání shody systém najde náš filtr a spustí požadovanou aktivitu.
Na stejném principu lze spustit další aktivity. Podívejte se na příklad. Pokud si příklad zkopírujete a podívejte se na dokumentaci k android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, uvidíte, že tento kód odpovídá řetězcové konstantě public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS"... Porovnejte s naším kódem. Můžete předpokládat, že aktivita nastavení pro offline režim má ve filtru zapsán tento řádek.
Název kategorie filtru android.intent.category.DEFAULTříká systému, aby provedl výchozí akci, kterou je spuštění aktivity. Jsou další jména, která nás zatím nezajímají.
A teď otázka k vyplnění. Co se stane, když vytvoříte další aktivitu a určíte stejný filtr jako druhá aktivita? Pojďme to zkontrolovat. Vytvořte v sobě třetí aktivitu a zkopírujte do ní blok s filtrem z druhé aktivity.
Klikněte na tlačítko v první aktivitě. Systém vás požádá o výběr požadované možnosti.
Pokud vyberete položku VŽDY, nebudete muset příště vybírat. Chcete-li obnovit výběr, přejděte do vlastností aplikace v Nastavení a najděte tlačítko Vymazat výchozí nastavení.
Spuštění aktivity podle jejího názvu
V konstruktoru Úmysl druhý parametr je třída. Předpokládejme ale, že existuje nějaká databáze, kde jsou uvedeny názvy aktivit a my potřebujeme spustit potřebnou aktivitu jejím jménem. Můžeme získat samotnou třídu na základě proměnné řetězce a spustit aktivitu.
Zkuste (// Celý název třídy aktivity String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // získání objektu Class Class>myClass = Class.forName (activityName); Intent intent = nový Intent (this, myClass); startActivity (záměr); ) catch (ClassNotFoundException e) (e.printStackTrace ();)
Nějak jsem měl za úkol přenést data ze služby do aktivity. Začali hledat řešení ve standardním SDK, ale protože nebyl čas, udělal jsem špatné řešení v podobě použití databáze. Otázka ale byla otevřená a po chvíli jsem přišel na správnější způsob, který je v SDK – pomocí tříd Message, Handler, Messenger.
Idea
Potřebujeme přenést data z aktivity do služby a naopak. jak to uděláme? Již máme vše, co potřebujeme k vyřešení našeho problému. Vše, co musíte udělat, je navázat službu na aktivitu pomocí bindService, předat potřebné parametry a trochu magie v podobě použití tříd Message. A kouzlo spočívá v použití proměnných instance Message a zejména responseTo. Tuto proměnnou potřebujeme, abychom mohli odkazovat na instanci služby Messanger z aktivace a ve službě na instanci aktivace v aplikaci Messanger. Ve skutečnosti to tak jednoduché není. Alespoň pro moji ne zrovna nejnadanější mysl. Částečně jen vylepšuji dokumentaci, která již existuje – Služby.Také dobrý příklad je na StackOverflow. V každém případě doufám, že článek bude užitečný alespoň někomu a nepracoval jsem zbytečně.
Příklad
Jako příklad implementujeme službu, která bude zvyšovat a snižovat hodnotu čítače a vracet výsledek do aktivity, do TextView. Kód rozložení vynechám, protože jsou zde dvě tlačítka a textové pole – vše je jednoduché.
Implementace
Dám celý aktivační kód:
Veřejná třída MainActivity rozšiřuje aktivitu (veřejný statický konečný řetězec TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; konečný Messenger messenger= nový Messenger (nový IncomingHandler ()); Messenger toServiceMessenger; @Override public void onCreate (Bundle SavedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); testTxt = (TextView) findViewById (R.id.test_txt); bindService (nový Intent (toto, TestService.class ), (testServConn = nové TestServiceConnection ()), Context.BIND_AUTO_CREATE);) @Override public void onDestroy () (super.onDestroy (); unbindService (testServConn);) public void countIncrClick (tlačítko Zobrazit) (Zpráva msg = Zpráva. získat (null, TestService.COUNT_PLUS); msg.replyTo = messenger; zkuste (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) public void countDecrClick (tlačítko Zobrazit) (Zpráva msg = Message.obtain (null, TestService.COUNT_MINUS); msg.replyTo = messenger; try (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) soukromá třída IncomingHandler rozšiřuje Handler (@Override public void handleMessage (Message msg) (přepnout (msg.what) (případ TestServic e.GET_COUNT: Log.d (TAG, "(aktivita) ... získat počet"); testTxt.setText ("" + msg.arg1); přestávka; ))) soukromá třída TestServiceConnection implementuje ServiceConnection (@Override public void onServiceConnected (název ComponentName, služba IBinder) (toServiceMessenger = nový Messenger (služba); // odeslání počáteční hodnoty počítadla Zpráva msg = Message.obtain (null, TestService.SET_COUNT) ; msg.replyTo = messenger; msg.arg1 = 0; // náš čítač try (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) @Override public void onServiceDisconnected (název ComponentName) ( )))
Nech mě to vysvětlit. Při vytváření aktivity se okamžitě navážeme na službu, implementujeme rozhraní ServiceConnection a v něm pošleme službě zprávu "nastav hodnotu čítače", předáme nulu a vytvoříme toServiceMessanger, předáme rozhraní IBinder konstruktoru. Mimochodem, služba musí tuto instanci vrátit, jinak to bude NPE. Tuto třídu používáme k odesílání zpráv službě. A tady je to kouzlo - do proměnné replyTo uložíme naši další instanci Messengeru - tu, která obdrží odpověď ze serveru a přes ni se provede spojení s aktivitou.
Abychom obdrželi zprávu od služby, používáme náš Handler a jednoduše hledáme proměnné, které potřebujeme, a provádíme s nimi akce. Kliknutím na tlačítka (metody countIncrClick, countDecrClick) odešleme službě požadavky s uvedením požadované akce v proměnné msg.what.
Package com.example.servicetest; importovat android.app.Service; import android.content. *; import android.os. *; importovat android.os.Process; importovat android.util.Log; veřejná třída TestService rozšiřuje službu (veřejná statická konečná int COUNT_PLUS = 1; veřejná statická konečná int COUNT_MINUS = 2; veřejná statická konečná int SET_COUNT = 0; veřejná statická konečná int GET_COUNT = 3; počet int = 0; IncomingHandler inHandler; Messenger messanger; Messenger toActivityMessenger; @Override public void onCreate () (super.onCreate (); vlákno HandlerThread = nový HandlerThread ("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start (); inHandler = nový IncomingHandler (thread.getLooper () (inHandler);) @Override public IBinder onBind (Intent arg0) (return messanger.getBinder ();) @Override public int onStartCommand (Intent intent, int příznaky, int startId) (return START_STICKY;) // soukromá třída obsluhy zpráv IncomingHandler rozšiřuje Handler (public IncomingHandler (Looper looper) (super (looper);) @Override public void handleMessage (Message msg) (//super.handleMessage(msg); toActivityMess enger = msg.replyTo; switch (msg.what) (case SET_COUNT: count = msg.arg1; Log.d (MainActivity.TAG, "(service) ... set count"); break; case COUNT_PLUS: count ++; Log.d (MainActivity .TAG , "(služba) ... počet plus"); break; case COUNT_MINUS: Log.d (MainActivity.TAG, "(service) ... count minus"); count--; break;) // odeslat hodnota čítače v aktivitě Message outMsg = Message.obtain (inHandler, GET_COUNT); outMsg.arg1 = počet; outMsg.replyTo = messanger; zkuste (if (toActivityMessenger! = null) toActivityMessenger.send (outMsg);) catch (RemoteException e) (e.printStackTrace ();))))
Vše analogicky s logikou v činnosti. Ani nevím, jestli musím něco vysvětlovat. Jediným bodem je, že okamžitě pošlu požadavek zpět na aktivitu v handleMessage pomocí magické proměnné replyTo a vytáhnutí požadovaného Messengeru výše. A druhý bod, který jsem již zmínil, je:
@Override public IBinder onBind (Intent arg0) (return messanger.getBinder ();)
bez kterého všechno spadne. Je to tato instance rozhraní, která bude předána ServiceConnection
Závěr
Celkově vzato. Takový je vymyšlený příklad interakce mezi aktivitami a službami. Zdá se mi, že jde o vcelku netriviální interakci, i když někomu může připadat jiná.
Otázky, upřesnění a další v osobním životě. V jakýchkoliv aspektech mohou být nepřesnosti, takže klidně napište a opravte.
Doufám, že příspěvek byl pro čtenáře užitečný.
Ahoj.
Data přijatá přes UART je nutné přenést do Activity. To lze provést vytvořením vlákna v Aktivitě, ve kterém se uspořádá smyčka while (! IsInterrupted ()) a načte se data z vyrovnávací paměti UART. Poté zavoláním vlákna uživatelského rozhraní aktivity - MainActivity.this.runOnUiThread (nové Runnable () proveďte s touto aktivitou potřebné akce. Pokud ale zavoláme jiné aktivity z hlavní aktivity, pak organizované vlákno nedovolí přenos data do nově vytvořené Aktivity.Pokud tomu dobře rozumím, aby mohla být data ze streamu přenesena do jakékoli Aktivity, musí být stream vytvořen ne v Aktivitě, ale ve Službě.
Otázka: data přišla přes UART, v streamu (který se vytváří v Servce) je potřeba přenést data do Aktivity, která je nyní aktivní, jak se to dá udělat a dělá se to vůbec?
1 odpověď
V každé aktivitě vytvořte handler. V metodě onResume () této aktivity to bindService (). Zde je jedním z parametrů rozhraní ServiceConnection. Implementujte jej alespoň se stejnou aktivitou. Implementujte v něm metodu onServiceConnected (). V tomto zpětném volání přichází jako jeden z parametrů samotná Služba. Nazvěte tedy tuto službu svou vlastní metodou setHandler (). Předejte Handler, který je v aktuální Aktivitě tam. Ale posílejte příchozí data přes UART do Služby na tomto Handleru. Mimochodem, Handler tradičně běží na hlavním vlákně, takže ke spuštění nebudete muset spustit RunOnUiThread.