Aplikacija se ne sastoji uvijek od jednog ekrana. Na primjer, kreirali smo vrlo koristan program a korisnik želi znati ko je autor. On klikne na dugme "O programu" i dođe na novi ekran, gde se nalaze korisne informacije o verziji programa, autoru, adresi sajta, koliko mačaka autor ima itd. Zamislite ekran aktivnosti kao web stranicu sa vezom na drugu stranicu. Ako pogledate kod u datoteci MainActivity.java iz prethodnih lekcija, vidjet ćete da naš razred MainActivity takođe se odnosi na Aktivnost(ili njegovih nasljednika) ili, tačnije, naslijeđeno od njega.
Javna klasa MainActivity proširuje AppCompatActivity
Kao što možete pretpostaviti, trebali bismo kreirati novu klasu, koja bi mogla izgledati ovako MainActivity i onda se nekako prebaci na njega kada se pritisne dugme.
Za eksperiment ćemo uzeti program iz prve lekcije i koristiti dugme za eksperimente (ili kreirati novi projekat sa jednim dugmetom na ekranu). Zatim krenimo nova forma prikazati korisne informacije... Na primjer, pokažimo korisniku šta mačka radi kada hoda lijevo-desno. Slažem se, ovo je veoma važna informacija, dajući trag svemiru.
Novu aktivnost ćemo kreirati ručno, iako studio ima gotove šablone. Ali nema ništa komplicirano i za bolje razumijevanje korisno je sve raditi ručno.
Kreirajmo novi XML markup fajl activity_about.xml u folderu res / izgled... Desni klik na folder raspored i birajte između kontekstni meni Novo | Datoteka resursa rasporeda... Pojavit će se okvir za dijalog. U prvo polje unesite naziv datoteke aktivnost_o... U drugom, morate unijeti korijenski element. Podrazumevano postoji ConstraintLayout... Obrišite tekst i unesite ScrollView... Unošenje nekoliko znakova dovoljno je da studio predloži gotove opcije, možete odmah pritisnuti Enter, ne čekajući potpuni unos riječi:
Dobit ćemo odgovarajuće prazno mjesto u koje ćemo umetnuti element. TextView.
Informacije će se preuzeti iz resursa, odnosno iz string resursa about_text... Sada je označen crvenom bojom, što ukazuje na nedostatak informacija. Mogao bi pritisnuti Alt + Enter i unesite tekst u dijaloški okvir. Ali za naš primjer, ova metoda neće raditi, jer će naš tekst biti višeredni, koristeći kontrolne znakove. Učinimo to drugačije. Hajde da otvorimo fajl res / values / strings.xml i ručno unesite sljedeći tekst:
Koristili smo najjednostavnije HTML oznake za formatiranje teksta kao što su , , ... Za naš primjer, dovoljno je podebljano istaknuti riječi koje se odnose na mačku i smjer kretanja. Za prevođenje teksta u nova linija koristiti simbole \ n... Dodajmo još jedan string resurs za naslov novog ekrana:
Shvatili smo maržu. Zatim morate kreirati klasu za prozor AboutActivity.java... Odaberite iz menija Fajl | Novo | Java klasa i popunite obavezna polja. U početku je dovoljno navesti samo ime. Zatim se bavite drugim poljima.
Hajdemo na prazno.
Čas je sada skoro prazan. Dodajmo kod ručno. Klasa mora naslijediti apstraktnu klasu Aktivnost ili njegovi rođaci kao FragmentActivity, AppCompatActivity itd. Mi dodajemo proširuje aktivnost... Klasa aktivnosti mora imati metodu onCreate ()... Stavljamo kursor miša u klasu i biramo iz menija Šifra | Nadjačajte metode(Ctrl + O). U dijalog box-u tražimo željenu klasu, za koju možete ukucati prve znakove na tastaturi brza pretraga... U kreiranoj metodi, morate pozvati metodu setContentView () koji će učitati pripremljene oznake na ekran. Dobićemo ovu opciju.
Paket ru.alexanderklimov.helloworld; import android.app.Activity; import android.os.Bundle; / ** * Kreirao Alexander Klimov 01.12.2014. * / javna klasa AboutActivity proširuje aktivnost (@Override zaštićena void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_about);))
Sada počinje ono najvažnije. Naš zadatak je da pređemo na novi ekran kada se klikne na dugme na prvom ekranu. Vrati se u razred MainActivity... Hajde da napišemo obrađivač klika na dugme:
Public void onClick (prikaz prikaza) (namjera namjere = nova namjera (MainActivity.this, AboutActivity.class); startActivity (namjera);)
Ovdje sam koristio metodu za rukovanje klikovima na gumbe koju sam opisao u lekciji.
Da biste pokrenuli novi ekran, morate kreirati instancu klase Namjera i navedite trenutnu klasu u prvom parametru, a klasu za prijelaz u drugom parametru, imamo ovo AboutActivity... Nakon toga se poziva metoda startActivity () koji pokreće novi ekran.
Ako sada pokušate testirati rad aplikacije u emulatoru, dobit ćete poruku o grešci. Šta smo pogriješili? Promašili smo jedan važan korak. Morate registrovati novu Aktivnost u manifestu AndroidManifest.xml... Pronađite ovu datoteku u svom projektu i dvaput kliknite na nju. Otvara se prozor za uređivanje fajla. Dodajte novu oznaku
Tako je string resurs dobro došao about_title... Pokrenite aplikaciju, kliknite na dugme i otvorite prozor O programu... Tako smo naučili kako da kreiramo novi prozor i pozovemo ga pritiskom na dugme. A na raspolaganju imamo i mega-praktičan program - sada će uvijek biti pri ruci nagovještaj šta mačka radi kada krene lijevo.
Još jednom vam skrećem pažnju na činjenicu da druga kreirana klasa aktivnosti mora naslijediti klasu Aktivnost ili njemu slično ( ListActivity i drugi), imaju XML markup datoteku (ako je potrebno) i budu upisani u manifest.
Nakon poziva metode startActivity () nova aktivnost će započeti (u ovom slučaju AboutActivity), postaje vidljiv i pomiče se na vrh steka koji sadrži komponente koje se izvršavaju. Prilikom pozivanja metode završiti () iz nove aktivnosti (ili kada se pritisne tipka za povratak) biće zatvorena i uklonjena iz steka. Programer također može navigirati do prethodne (ili bilo koje druge) aktivnosti koristeći isti metod. startActivity ().
Kako napraviti treći ekran - način za lijene
Programeri su, kao i mačke, lijena stvorenja. Uvijek zapamtite da za aktivnost trebate kreirati markup i klasu koja nasljeđuje od Aktivnost, i onda ne zaboravite da registrujete klasu u manifestu - pa nafig.
U tom slučaju izaberite iz menija Fajl | Novo | Aktivnost | Osnovna aktivnost(ili neki drugi šablon). Zatim će se pojaviti poznati prozor za kreiranje nove aktivnosti. Popunjavamo obavezna polja.
Kliknite na dugme Završi i aktivnost će biti spremna. Da biste to potvrdili, otvorite datoteku manifesta i provjerite ima li novog unosa. Ne govorim o fajlovima klasa i markupa, oni će se sami pojaviti pred vama.
Dodajte novo dugme na glavni ekran aktivnosti i napišite kod za prelazak na kreiranu aktivnost.
U početku bih vam savjetovao da ručno kreirate sve potrebne komponente za novu aktivnost kako biste razumjeli odnos između klase, oznake i manifesta. A kada ga dobijete, možete koristiti čarobnjak za kreiranje aktivnosti da ubrzate svoj rad.
Prijenos podataka između aktivnosti
Iskoristili smo najjednostavniji primjer za pozivanje drugog ekrana aktivnosti. Ponekad je potrebno ne samo pozvati novi ekran, već i prenijeti podatke na njega. Na primjer, korisničko ime. U tom slučaju morate koristiti posebno područje extraData koje klasa ima Namjera.
Region extraData je lista parova ključ / vrijednost koji se prenosi zajedno sa namerom. Nizovi se koriste kao ključevi, a za vrijednosti možete koristiti bilo koji primitivni tip podataka, nizove primitiva, objekte klase Bundle i sl.
Za prijenos podataka u drugu aktivnost koristite metodu stavitiExtra ():
Intent.putExtra ("Ključ", "Vrijednost");
Aktivnost primanja treba da pozove neki odgovarajući metod: getIntExtra (), getStringExtra () itd.:
Int count = getIntent (). GetIntExtra ("name", 0);
Ponovimo prethodni primjer. Već imamo tri aktivnosti. Prva aktivnost će imati dva tekstualna polja i dugme. Izgled može biti sljedeći:
Druga aktivnost SecondActivity ugradite element TextView, u kojem ćemo prikazati tekst primljen iz prve aktivnosti. Napišimo sljedeći kod za metodu onCreate () na drugoj aktivnosti.
@Override zaštićeni void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_second); String user = "Live"; String gift = "krofna rupa"; TextView infoTextView = (TextIdView) find. id.textViewInfo); infoTextView.setText (korisnik + ", dobili ste" + poklon);)
Ako sada pokrenemo program i samo pozovemo drugi prozor, kao što je opisano u prvom dijelu članka, vidjet ćemo zadanu oznaku Zhivotnoe, dobio si rupu od krofne... Slažem se, šteta je primati takve poruke.
Popravljamo situaciju. Dodajte kod za prvu aktivnost:
Public void onClick (View view) (EditText userEditText = (EditText) findViewById (R.id.editTextUser); EditText giftEditText = (EditText) findViewById (R.id.editTextGift); Intent intent = nova klasa Namjere (SecondActivity)); / gurnite tekst iz prvog tekstualnog polja u ključ korisničkog imena intent.putExtra ("korisničko ime", userEditText.getText (). toString ()); // gurnite tekst iz drugog tekstualnog polja u ključ za poklon intent.putExtra ( "gift ", giftEditText.getText (). toString ()); startActivity (namjera);)
Stavili smo predmet u poseban kontejner Namjera dva ključa sa vrijednostima preuzetim iz tekstualnih polja. Kada korisnik unese podatke u tekstualna polja, on će otići u ovaj kontejner i biti prebačen na drugu aktivnost.
Druga aktivnost bi trebala biti spremna za primanje toplih poruka kako slijedi (podebljano).
// Zadane vrijednosti String user = "Uživo"; String gift = "krofna rupa"; korisnik = getIntent (). getExtras (). getString ("korisničko ime"); dar = getIntent (). getExtras (). getString ("gift"); TextView infoTextView = (TextView) findViewById (R.id.textViewInfo); infoTextView.setText (korisnik + ", dobili ste" + poklon);
Sada poruka ne izgleda tako uvredljivo, ali čak i prijatno za neke ljude. U složenim primjerima, poželjno je dodati validaciju prilikom obrade podataka. Postoje situacije kada drugu aktivnost započnete s praznim podacima kao što je nullšto bi moglo srušiti aplikaciju.
U našem slučaju znamo da čekamo vrijednost niza, pa se kod može prepisati ovako:
Namjera namjera = getIntent (); korisnik = intent.getStringExtra ("korisničko ime");
Korisnik = getIntent (). GetStringExtra ("korisničko ime");
Program ima nedostatak - nije jasno od koga primamo pozdrave. Svaki dobro vaspitan majmun neće prihvatiti poklon od anonimnog izvora. Dakle, kao domaći zadatak, dodajte još jedno tekstualno polje da unesete ime korisnika koji šalje poruku.
Google preporučuje korištenje sljedećeg formata za ključeve: ime vašeg paketa kao prefiks, nakon čega slijedi sam ključ. U ovom slučaju, možete biti sigurni da je ključ jedinstven u interakciji s drugim aplikacijama. Ovako nešto:
Javni konačni statički String USER = "ru.alexanderklimov.myapp.USER";
Ko je podmetnuo mačku Vasku - vraćamo rezultat
Nije uvijek dovoljno jednostavno proslijediti podatke drugoj aktivnosti. Ponekad želite da dobijete informacije iz druge aktivnosti kada je zatvorite. Ako smo ranije koristili metodu startActivity (namjera namjere), onda postoji srodna metoda startActivityForResult (namjera, int RequestCode)... Razlika između metoda je dodatni parametar RequestCode... To je u osnovi samo cijeli broj koji možete sami sastaviti. To je potrebno kako bi se razlikovalo od koga je došao rezultat. Recimo da imate pet dodatnih ekrana i da im dodijelite vrijednosti od 1 do 5, a iz ovog koda možete odrediti čiji rezultat trebate obraditi. Možete koristiti vrijednost -1, tada će to biti isto kao i pozivanje metode startActivity (), tj. nećemo dobiti nikakav rezultat.
Ako koristite metodu startActivityForResult (), tada morate nadjačati metodu u kodu da biste primili rezultat onActivityResult () i obraditi rezultat. Zbunjen? Uzmimo primjer.
Pretpostavimo da ste detektiv. Pojavila se informacija da su sa stola uticajne osobe u restoranu ukradena dva komada kobasica i drugi proizvodi. Sumnja je pala na trojicu osumnjičenih - vranu, jebenog psića i mačku Vasku.
Jedan od posjetilaca je dao seriju fotografija sa svog ponty iPhone-a:
Tu je i iskaz drugog svjedoka: A Vaska sluša, ali jede.
Kreirajte novi projekat Sherlock sa dvije aktivnosti. Na prvom ekranu će se nalaziti dugme za prelazak na drugi ekran i tekstualna oznaka u kojoj će biti prikazano ime lopova.
Drugi ekran će imati grupu radio dugmadi:
Pošto očekujemo odgovor sa drugog ekrana, moramo koristiti metodu startActivityForResult () na prvom ekranu u koji prosljeđujemo varijablu CHOOSE_THIEF kao parametar RequestCode.
Statički konačni privatni int CHOOSE_THIEF = 0; public void onClick (Prikaz v) (Intent questionIntent = nova namjera (MainActivity.this, ChooseActivity.class); startActivityForResult (questionIntent, CHOOSE_THIEF);)
Pogledajte kod. Kada se klikne na dugme, radićemo sa drugim ekranom Odaberite Aktivnost i pokrenite drugi ekran, čekajući rezultat.
Idite na drugi ekran i napišite kod za drugu aktivnost.
Javni konačni statički String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick (View v) (Namjera answerIntent = nova namjera (); switch (v.getId ()) (slučaj R.id.radioDog: answerIntent.putExtra (THIEF, "Jebeni psić"); prekid; slučaj R.id .radioCrow: answerIntent.putExtra (THIEF, "Vrana"); break; case R.id.radioCat: answerIntent.putExtra (THIEF, "Przewalski's horse"); break; default: break;) setResult (RESULT_OK, answerIntent); završiti; završiti; ();)
Ovdje je sve jednostavno, kada detektiv odabere ime kriminalca, onda kroz metodu stavitiExtra () prosljeđujemo ime ključa i njegovu vrijednost.
Radi praktičnosti, nakon odabira, odmah zatvaramo drugi prozor i prosljeđujemo vrijednost prije zatvaranja RESULT_OK da jasno stavi do znanja da je izbor napravljen. Ako korisnik zatvori ekran pomoću dugmeta Nazad, vrijednost će biti proslijeđena RESULT_CANCELED.
Metoda setResult () uzima dva parametra: kod rezultata i sam rezultat, predstavljen kao namjera. Rezultirajući kod vam govori kojim rezultatom je aktivnost završila, po pravilu, ili je Aktivnost.RESULT_OK ili Aktivnost.RESULT_CANCELED... U nekim slučajevima, možda ćete morati koristiti vlastiti povratni kod za rukovanje varijacijama specifičnim za vašu aplikaciju. Metoda setResult () podržava bilo koju cjelobrojnu vrijednost.
Ako ćete podatke eksplicitno proslijediti kroz dugme, onda bi bilo lijepo dodati metodu završiti () zatvoriti drugu aktivnost kao nepotrebnu. Ako se prijelaz dogodi preko dugmeta Nazad, onda to nije potrebno.
Ako je korisnik zatvorio aktivnost kada je pritisnuto hardversko dugme za povratak, ili ako je metoda završiti () je pozvan prije metode setResult (), rezultirajući kod će biti postavljen na RESULT_CANCELED a vraćena namjera će pokazati vrijednost null.
Vraćamo se na prvi ekran. Prvi ekran čeka odgovor sa drugog ekrana, tako da morate dodati metodu kodu onActivityResult ().
@Override zaštićeni void onActivityResult (int requestCode, int resultCode, intent podaci) (super.onActivityResult (requestCode, resultCode, podaci); TextView infoTextView = (TextView) findViewById (R.id.textViewInfo); if (requestCode ==IEF) (CHOOSE) if (resultCode == RESULT_OK) (String thiefname = data.getStringExtra (ChooseActivity.THIEF); infoTextView.setText (thiefname);) else (infoTextView.setText (""); // obrišite tekst)))
Metoda očekuje dolazne podatke sa kodom CHOOSE_THIEF, a ako takvi podaci stignu, onda izdvaja vrijednost iz ključa OdaberiteActivity.THIEF koristeći metodu getStringExtra... Rezultirajuću vrijednost ispisujemo u TextView(promenljiva infoTextView). Ako smo se vratili na ekran preko dugmeta Nazad, onda jednostavno obrišemo tekst.
Kada se podređena aktivnost zatvori unutar roditeljske komponente, pokreće se rukovalac onActivityResult ()... Handler onActivityResult () uzima nekoliko parametara.
- Zatražite kod. Kod koji je korišten za pokretanje aktivnosti vraćajući rezultat
- Šifra rezultata. Kôd rezultata postavljen od strane podređene aktivnosti koji pokazuje kako je aktivnost završila. Može biti bilo koja cjelobrojna vrijednost, ali obično i jedno i drugo Aktivnost.RESULT_OK ili Aktivnost.RESULT_CANCELED
- Podaci. Namjera koja se koristi za pakiranje vraćenih podataka. U zavisnosti od svrhe podređene aktivnosti, može uključiti URI putanju koja predstavlja odabrani dio sadržaja. Alternativno (ili dodatno), aktivnost djeteta može vratiti informacije kao jednostavne vrijednosti, umotane u parametar namjere extras
Ako je aktivnost djeteta neočekivano prekinuta ili ako nije naveden kod rezultata prije zatvaranja, ovaj parametar će postati Aktivnost.RESULT_CANCELED.
Pokrećemo projekat, kliknemo na dugme i idemo na drugi ekran. Tu biramo jednu od opcija. Ako odaberete vranu, ekran će se zatvoriti i na prvom ekranu će se prikazati ime krivca. Ako odaberete psa, njegovo ime će biti prikazano.
Usput, ako odaberete mačku, njeno ime neće biti prikazano! Provjerite i uvjerite se sami. Pitaćete zašto? Elementary Watson! Počinilac nije uzeo u obzir jedan važan detalj. Restoran je praćen video kamerama, a video je i ko je zapravo ukrao kobasicu i uramio mačku. Vaska, drži se!
P.S. Ako se u početku nešto činilo neshvatljivim, onda će s vježbom mnogo toga postati jasno. Prijenos podataka između ekrana je uobičajen u aplikacijama i proučavat ćete primjer iznova i iznova.
P.P.S. Najbolja riba je kobasica. Znajući ovu slabost, nije bilo teško uokviriti mačku.
Korištenje filtera
U članku sam pokazao uobičajen način za prelazak na drugu aktivnost, kada je u metodi startActivity () prikazana je trenutna klasa i klasa za prelaz. Usput, klasa aktivnosti ne mora biti dio vaše aplikacije. Ako znate naziv klase iz druge aplikacije, možete se prebaciti na nju. Ali možete ići na drugu aktivnost na drugačiji način.
U praksi je to manje uobičajeno, ali može biti korisno. Recimo da već imate drugu aktivnost. Dodajte mu poseban filter u manifest:
I drugu aktivnost pokrećemo klikom na dugme na ovaj način.
Public void onClick (View view) (startActivity (nova namjera ("ru.alexanderklimov.testapplication.SecondActivity"));)
Zamenimo dugi niz konstantom.
Javni statički konačni string ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick (Prikaz pogleda) (startActivity (nova namjera (ACTION_SECOND_ACTIVITY));)
Pa šta smo uradili. Za drugu aktivnost dodali smo filter i odredili naziv za akcija u atributu android: ime... Radi praktičnosti, samo sam stavio puni naziv aktivnosti sa nazivom paketa u njega. Konstruktor klase Namjera ima nekoliko preopterećenih verzija. U jednoj verziji, možete odrediti string za akciju. Naznačili smo našu kreiranu akciju koja je registrovana u drugoj aktivnosti. Sistem gleda manifeste svih instaliranih aplikacija tokom rada. Prilikom traženja podudaranja, sistem pronalazi naš filter i pokreće željenu aktivnost.
Po istom principu mogu se pokrenuti i druge aktivnosti. Pogledajte primjer. Ako kopirate primjer sebi i pogledate dokumentaciju za android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, vidjet ćete da ovaj kod odgovara string konstanti public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS"... Uporedite sa našim kodom. Možete pretpostaviti da aktivnost postavki za offline način rada ima ovaj red upisan u filter.
Naziv kategorije filtera android.intent.category.DEFAULT govori sistemu da preduzme zadanu akciju, a to je pokretanje aktivnosti. Postoje i druga imena koja nas još ne zanimaju.
A sada pitanje za popunjavanje. Šta se dešava ako kreirate drugu aktivnost i navedete isti filter kao i druga aktivnost? Hajde da to proverimo. Kreirajte treću aktivnost u sebi i kopirajte blok sa filterom iz druge aktivnosti u njega.
Kliknite na dugme u prvoj aktivnosti. Sistem će od vas tražiti da odaberete opciju koju želite.
Ako odaberete stavku UVIJEK, sljedeći put nećete morati birati. Da poništite odabir, idite na svojstva aplikacije u Postavkama i pronađite dugme Obriši zadane postavke.
Pokretanje aktivnosti prema njenom imenu
U konstruktoru Namjera drugi parametar je klasa. Ali pretpostavimo da postoji neka vrsta baze podataka u kojoj su navedeni nazivi aktivnosti i da trebamo pokrenuti potrebnu aktivnost po njenom imenu. Možemo dobiti samu klasu na osnovu string varijable i pokrenuti aktivnost.
Pokušajte (// Puni naziv klase aktivnosti String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // nabavite Class Class objekt>myClass = Class.forName (ime aktivnosti); Namjera namjera = nova namjera (ovo, myClass); startActivity (namjera); ) catch (ClassNotFoundException e) (e.printStackTrace ();)
Nekako sam imao zadatak da prenesem podatke sa servisa na aktivnost. Počeli su tražiti rješenje u standardnom SDK-u, ali pošto nije bilo vremena, napravio sam loše rješenje u vidu korištenja baze podataka. Ali pitanje je bilo otvoreno i nakon nekog vremena sam shvatio ispravniji način, a to je u SDK-u - korištenje klasa Message, Handler, Messenger.
Ideja
Moramo prenijeti podatke iz aktivnosti u uslugu i obrnuto. Kako da ovo uradimo? Već imamo sve što nam je potrebno da riješimo naš problem. Sve što treba da uradite je da povežete uslugu sa aktivnošću koristeći bindService, prosledite potrebne parametre i malo magije u vidu korišćenja klasa Message. A magija je koristiti varijable instance poruke i, posebno, replyTo. Ova varijabla nam je potrebna da bismo mogli upućivati na instancu usluge Messanger od aktivacije iu servisu na instancu Messanger aktivacije. U stvari, nije tako jednostavno. Bar za moj ne najdarovitiji um. Djelomično samo poboljšavam dokumentaciju koja već postoji - Services.Takođe, postoji dobar primjer na StackOverflow-u. U svakom slučaju, nadam se da će članak biti koristan barem nekome i nisam uzalud radio.
Primjer
Kao primjer, implementiraćemo uslugu koja će povećati i smanjiti vrijednost brojača i vratiti rezultat aktivnosti, u TextView. Izostaviću kod za izgled, jer postoje dva dugmeta i tekstualno polje - sve je jednostavno.
Implementacija
Daću kompletan aktivacioni kod:
Javna klasa MainActivity proširuje aktivnost (javni statički konačni String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final Messenger messenger= novi Messenger (novi 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 (new Test.Stent. ), (testServConn = nova TestServiceConnection ()), Context.BIND_AUTO_CREATE);) @Override public void onDestroy () (super.onDestroy (); unbindService (testServConn);) public void countIncrClick (dugme Prikaz) (Poruka msg = Poruka. dobiti (null, TestService.COUNT_PLUS); msg.replyTo = messenger; pokušajte (toServiceMessenger.send (msg);) uhvatiti (RemoteException e) (e.printStackTrace ();)) public void countDecrClick (dugme Prikaz) (Poruka msg = Message.dobtain (null, TestService.COUNT_MINUS); msg.replyTo = messenger; pokušajte (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) privatna klasa IncomingHandler proširuje Handler (@Override public void handleMessage (poruka poruka) (prekidač (msg.what) (slučaj TestServic e.GET_COUNT: Log.d (TAG, "(aktivnost) ... dobiti broj"); testTxt.setText ("" + msg.arg1); break; ))) privatna klasa TestServiceConnection implementira ServiceConnection (@Override public void onServiceConnected (ime ComponentName, IBinder usluga) (toServiceMessenger = novi Messenger (usluga); // pošalji početna vrijednost brojač Poruka msg = Poruka.dobiti (null, TestService.SET_COUNT); msg.replyTo = messenger; msg.arg1 = 0; // naš brojač pokušaj (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) @Override public void onServiceDisconnected (ime ComponentName) ()))
Dopusti mi da objasnim. Prilikom kreiranja aktivnosti odmah se vežemo za servis, implementiramo ServiceConnection interfejs i u njemu šaljemo poruku servisu "postavi vrijednost brojača", prosljeđujemo nulu i kreiramo toServiceMessanger, prosljeđujući IBinder interfejs konstruktoru. Usput, usluga mora vratiti ovu instancu, inače će to biti NPE. Koristimo ovu klasu za slanje poruka servisu. I ovdje je magija - u varijablu replyTo spremamo našu drugu instancu Messengera - onu koja prima odgovor od servera i preko nje će se obavljati komunikacija sa aktivnošću.
Da bismo primili poruku od servisa, koristimo naš Handler i jednostavno tražimo varijable koje su nam potrebne i radimo na njima. Klikom na dugmad (metode countIncrClick, countDecrClick) šaljemo zahtjeve servisu, navodeći željenu radnju u varijabli msg.what.
Paket com.example.servicetest; import android.app.Service; import android.content.*; import android.os *; import android.os.Process; import android.util.Log; javna klasa TestService proširuje uslugu (javni statički konačni int COUNT_PLUS = 1; javni statički konačni int COUNT_MINUS = 2; javni statički konačni int SET_COUNT = 0; javni statički konačni int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; Messenger messanger; Messenger toActivityMessenger; @Override public void onCreate () (super.onCreate (); HandlerThread thread = new HandlerThread ("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start (); inHandler = novi IncomingHandler (thread.getLooper) (thread.getLooper) (inHandler);) @Override public IBinder onBind (Intent arg0) (return messanger.getBinder ();) @Override public int onStartCommand (Intent int, int flags, int startId) (return START_STICKY;) // privatna klasa rukovaoca poruka IncomingHandler proširuje Handler (javni IncomingHandler (Looper looper) (super (looper);) @Override public void handleMessage (poruka poruke) (//super.handleMessage(msg); toActivityMess enger = msg.replyTo; prekidač (msg.what) (slučaj SET_COUNT: count = msg.arg1; Log.d (MainActivity.TAG, "(service) ... set count"); prekid; slučaj COUNT_PLUS: count ++; Log.d (MainActivity .TAG , "(service) ... count plus"); break; case COUNT_MINUS: Log.d (MainActivity.TAG, "(service) ... count minus"); count--; break;) // poslati vrijednost brojača u aktivnosti Message outMsg = Message.dobtain (inHandler, GET_COUNT); outMsg.arg1 = broj; outMsg.replyTo = messanger; pokušajte (if (toActivityMessenger! = null) toActivityMessenger.send (outMsg);) catch (RemoteException e) (e.printStackTrace ();))))
Sve po analogiji sa logikom u aktivnosti. Ne znam ni da li treba nešto da objašnjavam. Jedina stvar je da odmah šaljem zahtjev nazad aktivnosti u handleMessage, koristeći magičnu varijablu replyTo i povlačeći željeni Messenger iznad. I druga stvar o kojoj sam već govorio je:
@Override javni IBinder onBind (Intent arg0) (povrati messanger.getBinder ();)
bez koje će sve pasti. To je ova instanca interfejsa koja će biti proslijeđena ServiceConnection
Zaključak
Sve u svemu. Takav je izmišljen primjer interakcije između aktivnosti i usluga. Čini mi se da je ovo prilično netrivijalna interakcija, iako nekome može izgledati drugačije.
Pitanja, pojašnjenja itd. u ličnoj. Može biti netačnosti u vezi sa bilo kojim aspektom, pa slobodno napišite i ispravite.
Nadam se da je post bio od pomoći čitaocima.
Zdravo.
Podatke primljene putem UART-a potrebno je prenijeti u Activity. Ovo se može učiniti kreiranjem niti u Aktivnosti u kojoj će se organizirati while (! IsInterrupted ()) petlja i čitati podaci iz UART bafera. Nakon toga, pozivanjem UI niti Aktivnosti - MainActivity.this.runOnUiThread (novi Runnable (), izvršite potrebne radnje sa ovom aktivnošću. Ali ako pozovemo druge aktivnosti iz glavne aktivnosti, tada organizirana nit ne dozvoljava prijenos podatke u novokreiranu aktivnost. Ako sam dobro shvatio da bi se podaci iz streama prenijeli na bilo koju aktivnost, stream mora biti kreiran ne u Aktivnosti, već u Servisu.
Pitanje: podaci su došli preko UART-a, u streamu (koji se kreira u Servcu) potrebno je prenijeti podatke u Aktivnost koja je sada aktivna, kako se to može uraditi i da li se to uopće radi?
1 odgovor
U svakoj aktivnosti kreirajte Handler. U metodi onResume () ove aktivnosti, on radi bindService (). Tamo, jedan od parametara je interfejs ServiceConnection. Provedite ga barem istom aktivnošću. Implementirajte onServiceConnected () metodu u njemu. U ovom povratnom pozivu, sama usluga dolazi kao jedan od parametara. Zato nazovite ovu uslugu svojom metodom setHandler (). Tu proslijedite Handler koji se nalazi u trenutnoj aktivnosti. Ali pošaljite dolazne podatke preko UART-a na servis na ovom rukovaocu. Usput, Handler tradicionalno radi na glavnoj niti, tako da nećete morati da pokrećete OnUiThread da biste ga izvršili.