Zdravo.
Potrebno je podatke primljene putem UART-a prenijeti u Aktivnost. To se može učiniti stvaranjem niti u Aktivnosti u kojoj se organizira while petlja (!isInterrupted()) i čitaju podaci iz UART međuspremnika. Nakon toga, pozivanjem UI niti Activity - MainActivity.this.runOnUiThread(new Runnable() , izvršite potrebne radnje s ovom aktivnošću. Ali ako pozovemo druge aktivnosti iz glavne aktivnosti, tada organizirana nit ne dopušta prosljeđivanje podataka u novostvorene aktivnosti Ako sam dobro razumio, da bi se podaci iz toka mogli prenijeti u bilo koju aktivnost, tok mora biti kreiran ne u aktivnosti, već u usluzi.
Pitanje: podaci su stigli preko UART-a, u streamu (koji se kreira u Servce-u) potrebno je prebaciti podatke u Activity, koja je sada aktivna, kako to učiniti i da li se to uopće radi?
1 odgovor
U svakoj aktivnosti kreirate rukovatelja. U metodi onResume() ove aktivnosti, bindService() je gotov. Jedan od parametara je sučelje ServiceConnection. Provedite ga s barem istom aktivnošću. U njemu implementirajte metodu onServiceConnected(). U ovom povratnom pozivu, jedan od parametara je sama usluga. Dakle, pozovite vlastitu metodu setHandler() ove usluge. Proslijedite tamo rukovatelja koji je u trenutnoj aktivnosti. Ali šaljite dolazne podatke putem UART-a u uslugu na ovom rukovatelju. Usput, Handler tradicionalno radi na glavnoj niti, tako da neće biti potrebe za pokretanjem OnUiThread.
Zadnja izmjena: 03.04.2018
Objekt Intent koristi se za prijenos podataka između dvije aktivnosti. Putem metode putExtra() možete dodati ključ i njegovu pridruženu vrijednost.
Na primjer, prosljeđivanje niza "Hello World" s ključem "hello" iz trenutne aktivnosti u SecondActivity:
// kreiranje Intent objekta za pokretanje SecondActivity Intent intent = new Intent(this, SecondActivity.class); // prosljeđivanje objekta s ključem "hello" i vrijednošću "Hello World" intent.putExtra("hello", "Hello World"); // pokretanje SecondActivity startActivity(namjera);
Za prijenos podataka koristi se metoda putExtra() koja vam omogućuje prijenos podataka najjednostavnijih tipova kao vrijednosti - String, int, float, double, long, short, byte, char, polja ovih tipova ili Serializable objekt sučelja.
Da biste dobili poslane podatke prilikom učitavanja SecondActivity, možete koristiti metodu get(), kojoj se prosljeđuje ključ objekta:
Argumenti paketa = getIntent().getExtras(); Naziv niza = arguments.get("hello").toString(); // Pozdrav svijete
Ovisno o vrsti podataka koje šaljemo, možemo koristiti brojne metode na objektu Bundle kada ga primimo. Svi oni uzimaju ključ objekta kao parametar. Glavni:
get() : generička metoda koja vraća vrijednost tipa Object. Sukladno tome, primajuće polje mora pretvoriti ovu vrijednost u traženi tip
getString() : vraća String objekt
getInt() : vraća int vrijednost
getByte() : vraća vrijednost bajta
getChar() : vraća char vrijednost
getShort() : vraća vrijednost tipa short
getLong() : vraća dugu vrijednost
getFloat() : vraća vrijednost float
getDouble() : vraća duplo
getBoolean() : vraća Booleovu vrijednost
getCharArray() : vraća niz char objekata
getIntArray() : vraća niz int objekata
getFloatArray() : vraća niz float objekata
getSerializable() : vraća objekt sučelja koji se može serijalizirati
Neka nam u projektu budu definirane dvije aktivnosti: MainActivity i SecondActivity.
U kodu SecondActivity definirat ćemo primanje podataka:
Paket com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; javna klasa SecondActivity proširuje AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16 ); Bundle arguments = getIntent().getExtras(); if(arguments!=null)( String name = arguments.get("name").toString(); String company = arguments.getString("company"); int cijena = arguments.getInt("cijena"); textView.setText("Naziv: " + naziv + "\nTvrtka: " + tvrtka + "\nCijena: " + cijena ) setContentView(textView) )
U ovom slučaju, u SecondActivity dobivamo sve podatke iz Bundle objekta i prikazujemo ih u tekstualnom polju TextView. Pretpostavlja se da će ovoj aktivnosti biti proslijeđena tri elementa - dva niza s ključevima ime i tvrtka i broj s ključem cijene.
Sada definirajmo prijenos podataka u SecondActivity. Na primjer, definirajmo sljedeće sučelje za MainActivity u datoteci activity_main.xml:
Ovdje su definirana tri tekstualna polja za unos podataka i gumb.
U klasi MainActivity definirat ćemo sljedeći sadržaj:
Paket com.example.eugene.serializeapp; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; javna klasa MainActivity proširuje AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = findViewById(R.id) .name); final EditText companyText(R.id.company); final EditText priceText(R.id.price); String name = nameText().toString(); cijena = Integer.parseInt(priceText.getText().toString()); Intent intent(this, SecondActivity.class); putExtra("company", company); intent.putExtra("cijena", cijena); startActivity(namjera) )
U rukovatelju klikom na gumb primamo podatke unesene u tekstualna polja EditText i prosljeđujemo ih objektu Intent pomoću metode putExtra(). Zatim pokrećemo SecondActivity.
Kao rezultat toga, kada kliknete na gumb, pokrenut će se SecondActivity, koji će primiti neke podatke unesene u tekstualna polja.
Prijenos složenih objekata
U gornjem primjeru prenosili su se jednostavni podaci - brojevi, nizovi. Ali možemo prenijeti i složenije podatke. U ovom slučaju koristi se mehanizam serijalizacije.
Na primjer, recimo da imamo klasu proizvoda definiranu u našem projektu:
Paket com.example.eugene.serializeapp; import java.io.Serializable; public class Product implements Serializable ( private String name; private String company; private int price; public Product(String name, String company, int price)( this.name = name; this.company = company; this.price = price; ) public String getName() ( return name; ) public void setName(String name) ( this.name = name; ) public String getCompany() ( return company; ) public void setCompany(String company) ( this.company = company; ) public int getPrice() ( povratna cijena; ) public void setPrice(int cijena) ( this.price = cijena; ) )
Vrijedno je napomenuti da ova klasa implementira Serializable sučelje. Sada promijenimo kod MainActivity:
Paket com.example.eugene.serializeapp; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; javna klasa MainActivity proširuje AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = findViewById(R.id) .name); final EditText companyText(R.id.company); final EditText priceText(R.id.price); String name = nameText().toString(); cijena = Integer.parseInt(priceText.getText().toString()); Product product = new Product(name, company, price); Intent intent(this, SecondActivity.class); intent.putExtra(Product.class .getSimpleName(), proizvod); startActivity(namjera) )
Sada se umjesto tri odvojena podatka prenosi jedan proizvodni objekt. Ključ je rezultat metode Product.class.getSimpleName(), koja u biti vraća naziv klase.
I promijenite klasu SecondActivity:
Paket com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; javna klasa SecondActivity proširuje AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16 ); Bundle arguments = getIntent().getExtras(); if(arguments!=null)(product = (Product) arguments.getSerializable(Product.class.getText()); " + product.getName() + "\nTvrtka: " + product.getCompany() + "\nCijena: " + String.valueOf(product.getPrice())); ) setContentView(textView); ) )
Metoda getSerializable() koristi se za dohvaćanje podataka jer klasa Product implementira Serializable sučelje. Na ovaj način možemo proslijediti jedan jedini objekt umjesto gomile različitih podataka.
Aplikacija se ne sastoji uvijek od jednog zaslona. Na primjer, napravili smo vrlo koristan program i korisnik želi znati tko je njegov autor. Klikne na gumb “O programu” i odvede se na novi ekran, gdje se nalaze korisne informacije o verziji programa, autoru, adresi web stranice, koliko mačaka autor ima itd. Zaslon aktivnosti zamislite kao web stranicu s vezom na drugu stranicu. Ako pogledate kod u datoteci MainActivity.java iz prethodnih lekcija, vidjet ćete da naš razred Glavna aktivnost također se odnosi na Aktivnost(odnosno njegovih nasljednika) odnosno, točnije, naslijeđeno od njega.
Javna klasa MainActivity proširuje AppCompatActivity
Kao što možda pretpostavljate, trebali bismo stvoriti novu klasu koja bi mogla biti slična Glavna aktivnost a onda se nekako prebaci na njega kad se pritisne gumb.
Za eksperiment ćemo uzeti program iz prve lekcije i koristiti gumb za eksperimente (ili izraditi novi projekt s jednim gumbom na ekranu). Zatim, stvorimo novi obrazac za prikaz korisnih informacija. Na primjer, pokažimo korisniku što mačka radi kada ide lijevo-desno. Slažem se, ovo je vrlo važna informacija koja daje ključ za razotkrivanje Svemira.
Novu aktivnost izradit ćemo ručno, iako studio ima gotove predloške. Ali tu nema ništa komplicirano i za bolje razumijevanje korisno je sve učiniti ručno.
Kreirajmo novu XML datoteku za označavanje activity_about.xml u mapi rez/izgled. Desni klik na mapu raspored i odaberite iz kontekstnog izbornika Novo | Datoteka resursa izgleda. Pojavit će se dijaloški okvir. U prvo polje unesite naziv datoteke aktivnost_o. U drugom morate unijeti korijenski element. Prema zadanim postavkama postoji ConstraintLayout. Obrišite tekst i unesite ScrollView. Unos nekoliko znakova dovoljan je da studio predloži gotove opcije, a da ne čekate da se unese cijela riječ;
Dobit ćete odgovarajuću prazninu u koju ćemo umetnuti element TextView.
Informacije će se dohvatiti iz resursa, točnije resursa niza o_tekstu. Sada je označen crvenom bojom, signalizirajući nedostatak informacija. Moglo se 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. Pa učinimo to drugačije. Otvorimo datoteku res/vrijednosti/nizovi.xml i ručno unesite sljedeći tekst:
Koristili smo najjednostavnije HTML oznake za oblikovanje teksta poput , , . Za naš primjer dovoljno je istaknuti masnim slovima riječi koje se odnose na mačku i smjer kretanja. Za pomicanje teksta u novi red koristite simbole \n. Dodajmo još jedan izvor niza za naslov novog zaslona:
Shvatili smo oznake. Zatim trebate stvoriti klasu za prozor AboutActivity.java. Odaberite iz izbornika Datoteka | Novo | Java klasa i ispunite potrebna polja. U početku je dovoljno navesti samo ime. Onda ćeš se baviti drugim poljima.
Uzmimo prazninu.
Sada je razred gotovo prazan. Dodajmo kôd ručno. Klasa mora naslijediti od apstraktne klase Aktivnost ili njegovi rođaci poput FragmentActivity, AppCompatActivity itd. Dodajmo proširuje Aktivnost. Klasa aktivnosti mora imati metodu onCreate(). Postavite kursor miša unutar klase i odaberite iz izbornika Kod | Nadjačavanje metoda(Ctrl+O). U dijaloškom okviru tražimo traženu klasu; možete upisati prve znakove na tipkovnici za brzo pretraživanje. U kreiranoj metodi morate pozvati metodu setContentView(), koji će učitati pripremljenu oznaku na zaslon. Imat ć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 protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Sada dolazi najvažniji dio. Naš zadatak je prijeći na novi ekran kada kliknemo gumb na prvom ekranu. Vratimo se u razred Glavna aktivnost. Napišimo rukovatelj klikom na gumb:
Public void onClick(View view) ( Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Ovdje sam koristio metodu obrade klika na gumb opisanu u lekciji.
Da biste pokrenuli novi zaslon, morate stvoriti instancu klase Namjera i navedite trenutnu klasu u prvom parametru, a klasu u koju idete u drugom, imamo ovo O Aktivnosti. Nakon toga se poziva metoda startActivity(), koji pokreće novi zaslon.
Ako sada pokušate testirati aplikaciju u emulatoru, primit ćete poruku o pogrešci. Što smo učinili krivo? Propustili smo jedan važan korak. Morate registrirati novi Aktivnost u manifestu AndroidManifest.xml. Pronađite ovu datoteku u svom projektu i dvaput kliknite na nju. Otvorit će se prozor za uređivanje datoteke. Dodajte novu oznaku
Ovo je mjesto gdje izvor niza dolazi od koristi o_naslovu. Pokrećemo aplikaciju, kliknemo na gumb i dobijemo prozor O programu. Tako smo naučili kako napraviti novi prozor i pozvati ga klikom na gumb. A na raspolaganju nam je i megapraktičan program - sada ćemo uvijek pri ruci imati natuknicu što mačka radi kad krene lijevo.
Još jednom imajte na umu da druga kreirana klasa aktivnosti mora naslijediti klasu Aktivnost ili slični ( ListActivity itd.), imati XML datoteku za označavanje (ako je potrebna) i biti navedena u manifestu.
Nakon poziva metode startActivity() pokrenut će se nova aktivnost (u ovom slučaju O Aktivnosti), postat će vidljiv i pomaknuti se na vrh hrpe koja sadrži aktivne komponente. Prilikom pozivanja metode Završi() od nove aktivnosti (ili kada se pritisne hardverska tipka za povratak) bit će zatvoren i uklonjen sa stoga. Programer također može navigirati do prethodne (ili bilo koje druge) aktivnosti koristeći istu metodu startActivity().
Izrada trećeg ekrana - metoda za lijene
Programeri su, poput mačaka, lijena bića. Uvijek imajte na umu da za aktivnost morate stvoriti oznake i klasu koja nasljeđuje Aktivnost, a zatim ne zaboravite registrirati klasu u manifestu - dobro.
U tom slučaju odaberite iz izbornika Datoteka | Novo | Aktivnost | Osnovna djelatnost(ili neki drugi predložak). Zatim će se pojaviti poznati prozor za stvaranje nove aktivnosti. Ispunite obavezna polja.
Kliknite na gumb Završi i aktivnost će biti spremna. Da biste to provjerili, otvorite datoteku manifesta i potražite novi unos. O class i markup datotekama i ne govorim, one će se same pojaviti pred vama.
Sami dodajte novi gumb na glavni zaslon aktivnosti i napišite kod za prebacivanje na stvorenu aktivnost.
Za početak bih vam savjetovao da ručno izradite sve potrebne komponente za novu aktivnost kako biste razumjeli odnos između klase, oznake i manifesta. A kada se snađete, možete upotrijebiti čarobnjak za stvaranje aktivnosti da ubrzate svoj rad.
Prijenos podataka između aktivnosti
Koristili smo jednostavan primjer za pozivanje drugog zaslona aktivnosti. Ponekad ne samo da trebate pozvati novi zaslon, već i prenijeti podatke na njega. Na primjer, korisničko ime. U ovom slučaju morate koristiti posebno područje extraData, koje razred ima Namjera.
Regija extraData je popis parova ključ/vrijednost, koji se prenosi uz namjeru. Nizovi se koriste kao ključevi, a bilo koji primitivni tipovi podataka, nizovi primitiva, objekti klase mogu se koristiti za vrijednosti Paket i tako dalje.
Za prijenos podataka u drugu aktivnost upotrijebite metodu putExtra():
Intent.putExtra("Ključ", "Vrijednost");
Aktivnost primanja mora pozvati neku odgovarajuću metodu: getIntExtra(), getStringExtra() itd.:
Int count = getIntent().getIntExtra("name", 0);
Ponovimo prethodni primjer. Već imamo tri aktivnosti. Prva aktivnost će imati dva tekstualna polja i gumb. Izgled može biti sljedeći:
Kod druge aktivnosti Druga aktivnost postaviti element TextView, u kojem ćemo prikazati tekst dobiven iz prve aktivnosti. Napišimo sljedeći kod za metodu onCreate() na drugoj aktivnosti.
@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String gift = "donut hole"; TextView infoTextView = (TextView)findViewById( R .id.textViewInfo); infoTextView.setText(user + ", dobili ste " + dar);
Ako sada pokrenemo program i jednostavno pozovemo drugi prozor, kao što je opisano u prvom dijelu članka, tada ćemo vidjeti zadani natpis Životinjo, dali su ti rupu od krafne. Slažete se, prilično je neugodno primati takve poruke.
Ispravimo situaciju. Dodajte kod prvoj aktivnosti:
Public void onClick(View view) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Namjera namjere = nova namjera(MainActivity.this, SecondActivity. class); // gurnite tekst iz prvog tekstualnog polja u ključ korisničkog imena intent.putExtra("username", userEditText.getText().toString()); // gurnite tekst iz drugog tekstualnog polja u ključ poklona intent.putExtra("dar" ", giftEditText.getText().toString()); startActivity(namjera); )
Predmet smo stavili u poseban spremnik Namjera dva ključa s vrijednostima koje su preuzete iz tekstualnih polja. Kada korisnik unese podatke u tekstualna polja, oni će ići u ovaj spremnik i biti proslijeđeni drugoj aktivnosti.
Druga aktivnost trebala bi biti spremna za toplo primanje poruka kako slijedi (podebljano).
// Zadane vrijednosti String user = "Animal"; Struna dar = "rupa od krafne"; korisnik = getIntent().getExtras().getString("korisničko ime"); dar = getIntent().getExtras().getString("dar"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , dobili ste " + dar);
Sada poruka izgleda manje uvredljivo, a nekima čak i ugodno. U složenim primjerima preporučljivo je dodati provjeru prilikom obrade podataka. Mogu postojati situacije u kojima pokrenete drugu aktivnost s praznim podacima tipa ništavan, što može uzrokovati rušenje aplikacije.
U našem slučaju, znamo da očekujemo vrijednost niza, pa se kod može prepisati ovako:
Namjera namjere = getIntent(); korisnik = intent.getStringExtra("korisničko ime");
Korisnik = getIntent().getStringExtra("korisničko ime");
Program ima nedostatak - nije jasno od koga primamo čestitke. Nijedan dobro odgojen majmun neće prihvatiti dar od anonimnog izvora. Kao domaću zadaću dodajte još jedno tekstualno polje za unos imena korisnika koji šalje poruku.
Google preporučuje korištenje sljedećeg formata za ključeve: naziv vašeg paketa kao prefiks, nakon kojeg slijedi sam ključ. U tom slučaju možete biti sigurni u jedinstvenost ključa u interakciji s drugim aplikacijama. Nešto kao ovo:
Javni završni statički niz USER = "ru.alexanderklimov.myapp.USER";
Tko je smjestio mačku Vasku - vraćamo rezultat
Nije uvijek dovoljno jednostavno proslijediti podatke drugoj aktivnosti. Ponekad morate dobiti informacije od druge aktivnosti kada je ona zatvorena. Ako smo ranije koristili metodu startActivity(namjera namjere), onda postoji srodna metoda startActivityForResult(namjera namjere, int kod zahtjeva). Razlika između metoda je dodatni parametar RequestCode. To je u osnovi samo cijeli broj do kojeg možete sami doći. To je potrebno kako bi se razlikovalo od koga je rezultat došao. Recimo da imate pet dodatnih ekrana i dodijelite im vrijednosti od 1 do 5, a pomoću ovog koda možete odrediti čiji rezultat trebate obraditi. Možete koristiti vrijednost -1, tada će to biti isto kao pozivanje metode startActivity(), tj. nećemo dobiti nikakve rezultate.
Ako koristite metodu startActivityForResult(), tada morate nadjačati metodu u svom kodu da biste dobili rezultat onActivityResult() i obraditi rezultat. Zbunjeni? Pogledajmo primjer.
Recimo da ste detektiv. Zaprimljena je informacija da su u ugostiteljskom objektu sa stola jedne utjecajne osobe ukradena dva komada kobasica i drugi proizvodi. Sumnja je pala na troje osumnjičenih - vranu, jebenog psa i mačku Vasku.
Jedan od posjetitelja dao je niz fotografija sa svog paradnog iPhonea:
Tu je i iskaz drugog svjedoka: A Vaska sluša i jede.
Napravite novi projekt Sherlock sa dvije aktivnosti. Na prvom ekranu nalazit će se gumb za prebacivanje na drugi ekran i tekstualna oznaka u kojoj će biti prikazano ime lopova.
Na drugom ekranu bit će skupina prekidača:
Budući da očekujemo odgovor s drugog zaslona, moramo upotrijebiti ovu metodu startActivityForResult() na prvom ekranu u koji ćemo proslijediti varijablu IZABERI_LOPOVA kao parametar RequestCode.
Static final private int CHOOSE_THIEF = 0; public void onClick(View v) ( Intent questionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Pogledaj kod. Kada kliknemo na gumb, radit ćemo s drugim zaslonom Odaberite Aktivnost i pokrenite drugi zaslon čekajući rezultat.
Idemo na drugi zaslon i napišimo kod za drugu aktivnost.
Javni završni statički niz THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Jebeni psić"); break; case R.id .radioCrow: answerIntent(THIEF, "Crow"; case R.id.putExtra(THIEF, "Przewalski's Horse"); setResult(RESULT_OK, answerIntent); ;
Ovdje je sve jednostavno, kada detektiv izabere ime kriminalca, onda kroz metodu putExtra() prosljeđujemo ime ključa i njegovu vrijednost.
Radi praktičnosti, nakon odabira, odmah zatvaramo drugi prozor i prije zatvaranja prenosimo vrijednost REZULTAT_OK, kako bi bilo jasno da je izbor napravljen. Ako korisnik zatvori zaslon preko gumba Natrag, vrijednost će biti proslijeđena REZULTAT_OTKAZAN.
metoda postaviRezultat() uzima dva parametra: rezultirajući kod i sam rezultat, predstavljen kao namjera. Rezultirajući kod vam govori kakav je bio rezultat aktivnosti, u pravilu i jest Aktivnost.RESULT_OK, ili Aktivnost.RESULT_CANCELED. U nekim slučajevima morate koristiti vlastiti povratni kod za obradu varijacija specifičnih za vašu aplikaciju. metoda postaviRezultat() podržava bilo koju cjelobrojnu vrijednost.
Ako ćete prosljeđivati podatke izričito kroz gumb, onda bi bilo dobro dodati metodu Završi() zatvoriti drugu aktivnost kao nepotrebnu. Ako se prijelaz dogodi putem gumba Natrag, to nije potrebno.
Ako je aktivnost zatvorio korisnik pritiskom na hardverski gumb za povratak ili ako je metoda Završi() je pozvan prije metode postaviRezultat(), rezultirajući kod bit će postavljen na REZULTAT_OTKAZAN, a vraćena namjera pokazat će vrijednost ništavan.
Vraćamo se na prvi ekran. Prvi ekran čeka na odgovor drugog ekrana, tako da trebate dodati metodu kodu 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(thiefname); )else ( infoTextView.setText(""); // brisanje teksta ) ) )
Metoda očekuje dolazne podatke s kodom IZABERI_LOPOVA, a ako takvi podaci stignu, dohvaća vrijednost iz ključa Odaberite Aktivnost.LOPOD pomoću metode getStringExtra. Prikazujemo dobivenu vrijednost u TextView(varijabilno infoTextView). Ako smo se vratili na ekran preko tipke Natrag, tada jednostavno brišemo tekst.
Kada se podređena aktivnost zatvori unutar nadređene komponente, aktivira se rukovatelj onActivityResult(). rukovatelj onActivityResult() prihvaća nekoliko parametara.
- Kod zahtjeva. Kod koji se koristi za pokretanje aktivnosti koja vraća rezultat
- Rezultirajući kod. Šifra rezultata koju je postavila podređena aktivnost koja pokazuje kako je posao dovršen. To može biti bilo koja cjelobrojna vrijednost, ali obično bilo koja Aktivnost.RESULT_OK, ili Aktivnost.RESULT_CANCELED
- Podaci. Namjera koja se koristi za pakiranje vraćenih podataka. Ovisno o svrsi dječje aktivnosti, ona može uključivati URI stazu koja predstavlja odabrani dio sadržaja. Alternativno (ili komplementarno), dječja aktivnost može vratiti informacije kao jednostavne vrijednosti umotane u parametar namjere dodaci
Ako je dječja aktivnost neočekivano prekinuta ili ako nije navedena šifra rezultata prije zatvaranja, ovaj će parametar postati Aktivnost.RESULT_CANCELED.
Pokrećemo projekt, kliknemo na gumb i idemo na drugi ekran. Tamo biramo jednu od opcija. Ako odaberete vranu, ekran će se zatvoriti i ime kriminalca će se pojaviti na prvom ekranu. Ako odaberete psa, prikazat će se njegovo ime.
Usput, ako odaberete mačku, njeno ime neće biti prikazano! Provjerite i uvjerite se sami. Pitat ćete zašto? Osnovno Watsone! Zločinac nije uzeo u obzir jedan važan detalj. Restoran je bio pod nadzorom video kamera, a na snimci se vidjelo tko je zapravo ukrao kobasicu i smjestio mački. Vaska, izdrži!
p.s. Ako vam se isprva nešto činilo nejasnim, s praksom će puno toga postati jasnije. Prijenos podataka između zaslona uobičajen je u aplikacijama, a primjer ćete proučavati više puta.
P.P.S. Najbolja riba je kobasica. Znajući tu slabost, mačku nije bilo teško smjestiti.
Korištenje filtara
U članku sam pokazao uobičajeni način prebacivanja na drugu aktivnost kada ste u metodi startActivity() Označeni su trenutni razred i razred koji se prenosi. Usput, razred aktivnosti ne mora biti dio vaše prijave. Ako znate naziv klase iz druge aplikacije, možete se prebaciti na nju. Ali možete prijeći na drugu aktivnost na drugi način.
U praksi je rjeđi, ali može biti koristan. Recimo da već imate drugu aktivnost. U manifestu ćemo mu dodati poseban filter:
I pokrećemo drugu aktivnost klikom na gumb na ovaj način.
Public void onClick(View view) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity")); )
Zamijenimo dugačak niz konstantom.
Javni statički konačni niz ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(View view) ( startActivity(nova namjera(ACTION_SECOND_ACTIVITY)); )
Pa što smo učinili. Za drugu aktivnost registrirali smo filtar i naveli naziv za akcijski u atributu android:ime. Radi praktičnosti, samo sam stavio puni naziv aktivnosti s nazivom paketa. Konstruktor klase Namjera ima nekoliko preopterećenih verzija. U jednoj verziji možete navesti niz za radnju. Naznačili smo našu kreiranu akciju koja je registrirana u drugoj aktivnosti. Tijekom rada sustav pregledava manifeste svih instaliranih aplikacija. Prilikom traženja podudaranja, sustav pronalazi naš filter i pokreće traženu aktivnost.
Na isti princip možete 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 konstanti niza public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Usporedite s našim kodom. Možete pretpostaviti da aktivnost postavki za izvanmrežni način rada ima ovaj redak u svom filtru.
Naziv kategorije filtra android.intent.category.DEFAULT govori sustavu da izvrši zadanu radnju, a to je pokretanje aktivnosti. Ima još imena koja nas još ne zanimaju.
A sada konačno pitanje. Što se događa ako stvorite drugu aktivnost i navedete isti filtar kao drugu aktivnost? Idemo to provjeriti. Napravite treću aktivnost i u nju kopirajte blok s filtrom iz druge aktivnosti.
Kliknite na gumb u prvoj aktivnosti. Sustav će od vas tražiti da odaberete željenu opciju.
Ako odaberete STALNO, sljedeći put nećete morati birati. Za poništavanje odabira idite na svojstva aplikacije u postavkama i pronađite gumb Obriši zadane postavke.
Pokrenite aktivnost pod njenim imenom
U konstruktoru Namjera drugi parametar je klasa. Ali pretpostavimo da postoji neka vrsta baze podataka u kojoj su navedeni nazivi aktivnosti i trebamo pokrenuti željenu aktivnost pod njenim imenom. Možemo dobiti samu klasu na temelju string varijable i pokrenuti aktivnost.
Pokušajte ( // Puni naziv klase aktivnosti String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // dohvatite objekt klase>myClass = Class.forName(activityName); Namjera namjere = nova namjera(ovo, mojRazred); startActivity(namjera); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
Nekako sam imao zadatak prebaciti podatke iz usluge u aktivnost. Krenula je potraga za rješenjem u standardnom SDK-u, ali kako 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 skužio ispravniju metodu, koja se nalazi u SDK-u - koristeći klase Message, Handler, Messenger.
Ideja
Moramo prenijeti podatke iz aktivnosti u uslugu i natrag. Kako ćemo to učiniti? Već imamo sve što nam je potrebno za rješavanje našeg problema. Sve što trebate je povezati uslugu s aktivnošću koristeći bindService, proslijediti potrebne parametre i malo magije u obliku korištenja klasa poruka. Čarolija je u korištenju varijabli instance poruke i, posebno, replyTo. Ova nam je varijabla potrebna kako bismo mogli pristupiti instanci usluge Messanger iz aktivnosti, au usluzi instanci aktivnosti Messanger. Zapravo, nije tako jednostavno. Barem za moj manje nadareni um. Djelomično samo poboljšavam dokumentaciju koja već postoji - Usluge Također, postoji dobar primjer na StackOverflowu. U svakom slučaju, nadam se da će članak biti koristan barem nekome i moj rad nije bio uzaludan.
Primjer
Kao primjer, implementirat ćemo uslugu koja će povećati i smanjiti vrijednost brojača i vratiti rezultat u aktivnost, u TextView. Izostavit ću kod izgleda jer postoje dva gumba i tekstualno polje - sve je jednostavno.
Provedba
Evo kompletnog aktivacijskog koda:
Javna klasa MainActivity proširuje Activity ( public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final Messenger messenger = new Messenger(new 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(this, TestService.class), (testServConn = new TestServiceConnection()), Context .BIND_AUTO_CREATE); ) @Override public void onDestroy())( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(View button)( Message msg = Message.obtain(null, TestService.COUNT_PLUS); msg. replyTo = messenger; pokušaj ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(View button)( Message msg = Message.obtain(null, TestService.COUNT_MINUS); msg .replyTo = glasnik; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) private class IncomingHandler extends Handler ( @Override public void handleMessage(Message msg)( switch (msg.what) ( case TestService. GET_COUNT: Log.d(TAG, "(activity)...get count"); testTxt.setText(""+msg.arg1)); ime, usluga IBinder) ( toServiceMessenger = novi Messenger(usluga); //pošalji početnu vrijednost brojača Poruka msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = glasnik; msg.arg1 = 0; / /naš brojač pokušaj ( toServiceMessenger.send(msg); ) uhvati (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
Dopustite da objasnim. Prilikom kreiranja aktivnosti odmah se povezujemo sa servisom, implementirajući ServiceConnection sučelje iu njemu servisu šaljemo poruku “postavi vrijednost brojača”, prosljeđujući nulu i kreirajući toServiceMessanger, prosljeđujući IBinder sučelje konstruktoru. Usput, ovu kopiju morate vratiti servisu, inače će doći do NPE-a. Pomoću ove klase šaljemo poruke servisu. I tu je magija - u varijablu replyTo spremamo našu drugu instancu Messengera - onu koja prima odgovor od servera i preko koje će se odvijati komunikacija s aktivnošću.
Da bismo primili poruku od usluge, koristimo naš Handler i jednostavno tražimo varijable koje su nam potrebne i poduzimamo radnje na njima. Klikom na gumbe (metode countIncrClick, countDecrClick) šaljemo zahtjeve servisu, označavajući željenu akciju u varijabli msg.what.
Paket com.example.servicetest; import android.app.Service; uvoz android.content.*; uvoz android.os.*; import android.os.Process; import android.util.Log; javna klasa TestService proširuje uslugu ( public static final int COUNT_PLUS = 1; public static final int COUNT_MINUS = 2; public static final int SET_COUNT = 0; public static final 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 = new IncomingHandler(thread.getLooper()); messanger = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int flags, int startId) ( return START_STICKY; ) //poruka aktivnost rukovatelja privatna klasa IncomingHandler extends Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Message msg)( //super.handleMessage(msg); toActivityMessenger = 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 , "(service)...count plus"; case COUNT_MINUS: Log.d(MainActivity.TAG, "(service)...count minus"); Message.obtain(inHandler, GET_COUNT ); outMsg.arg1 = broj; outMsg.replyTo = messanger; pokušaj ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) uhvati (RemoteException e) ( e.printStackTrace(); ) ) ) )
Sve je slično logici u Activitu. Ne znam ni trebam li išta objašnjavati. Jedina poanta je da odmah šaljem zahtjev natrag na aktivnost u handleMessage, koristeći čarobnu varijablu replyTo i izvlačeći željeni Messenger iznad. A druga točka o kojoj sam već govorio je:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
bez koje će sve propasti. To je ova instanca sučelja koja će biti proslijeđena ServiceConnection-u
Zaključak
Sve u svemu. Ovo je nategnut primjer interakcije između aktivnosti i usluge. Čini mi se da je ovo prilično netrivijalna interakcija, iako drugi možda misle drugačije.
Pitanja, pojašnjenja itd. na PM. Možda postoje netočnosti u vezi s nekim aspektima, stoga slobodno napišite i ispravite.
Nadam se da je post bio koristan čitateljima.