Buna ziua.
Este necesar să transferați datele primite prin UART către Activitate. Acest lucru se poate face prin crearea unui fir în Activitate în care să se organizeze o buclă while (!isInterrupted()) și să se citească datele din bufferul UART. După aceea, apelând firul UI Activity - MainActivity.this.runOnUiThread(new Runnable() , efectuați acțiunile necesare cu această Activitate. Dar dacă apelăm alte Activități din Activitatea principală, atunci firul organizat nu permite transmiterea datelor către Activitățile nou create Dacă am înțeles corect, pentru ca datele dintr-un flux să fie transferate în orice Activitate, fluxul trebuie creat nu în Activitate, ci în Serviciu.
Întrebare: datele au ajuns prin UART, într-un flux (care este creat în Servce) este necesar să transferați date către Activitate, care este acum activă, cum se poate face acest lucru și se face chiar acest lucru?
1 raspuns
În fiecare activitate creați un Handler. În metoda onResume() a acestei activități, bindService() este finalizat. Unul dintre parametrii de acolo este interfața ServiceConnection. Implementați-l cu cel puțin aceeași activitate. Implementați metoda onServiceConnected() în ea. În acest apel invers, unul dintre parametri este Serviciul în sine. Deci, apelați metoda setHandler() proprie a acestui serviciu. Treceți acolo Handler-ul care se află în Activitatea curentă. Dar trimiteți datele primite prin UART către Service pe acest Handler. Apropo, Handler rulează în mod tradițional pe firul principal, deci nu va fi nevoie să rulațiOnUiThread.
Ultima actualizare: 04/03/2018
Un obiect Intent este utilizat pentru a transfera date între două activități. Prin metoda putExtra() puteți adăuga o cheie și valoarea asociată acesteia.
De exemplu, trecerea șirului „Hello World” cu cheia „hello” din activitatea curentă la SecondActivity:
// crearea unui obiect Intent pentru a lansa SecondActivity Intent intent = new Intent(this, SecondActivity.class); // trecerea unui obiect cu cheia "hello" și valoarea "Hello World" intent.putExtra("hello", "Hello World"); // începe SecondActivity startActivity(intent);
Pentru a transfera date, se folosește metoda putExtra(), care vă permite să transferați date de cele mai simple tipuri ca valoare - String, int, float, double, long, short, byte, char, arrays de aceste tipuri sau un Serializable obiect de interfață.
Pentru a obține datele trimise la încărcarea SecondActivity, puteți utiliza metoda get(), căreia i se transmite cheia obiectului:
Bundle arguments = getIntent().getExtras(); Nume șir = arguments.get("bună ziua").toString(); // Salut Lume
În funcție de tipul de date pe care le trimitem, putem folosi o serie de metode pe obiectul Bundle atunci când îl primim. Toate iau ca parametru cheia obiectului. Principalele:
get() : o metodă generică care returnează o valoare de tip Object. În consecință, câmpul de recepție al acestei valori trebuie convertit la tipul dorit
getString() : returnează un obiect String
getInt() : returnează o valoare int
getByte() : returnează o valoare de octet
getChar() : returnează o valoare char
getShort() : returnează o valoare de tip short
getLong() : returnează o valoare lungă
getFloat() : returnează o valoare flotantă
getDouble() : returnează un dublu
getBoolean() : returnează o valoare booleană
getCharArray() : returnează o matrice de obiecte char
getIntArray() : returnează o matrice de obiecte int
getFloatArray() : returnează o matrice de obiecte float
getSerializable() : returnează un obiect de interfață Serializable
Să avem două activități definite în proiectul nostru: MainActivity și SecondActivity.
În codul SecondActivity, vom defini primirea datelor:
Pachetul com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; clasa publică SecondActivity extinde AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16, 16, 16) ); Bundle arguments = getIntent().getExtras(); if(arguments!=null)( String name = arguments.get("name").toString(); String company = arguments.getString("company"); int preț = arguments.getInt("preț"); textView.setText("Nume: " + nume + "\nCompanie: " + companie + "\nPreț: " + preț ) setContentView(textView) )
În acest caz, în SecondActivity obținem toate datele din obiectul Bundle și le afișăm în câmpul text TextView. Se presupune că la această activitate vor fi trecute trei elemente - două șiruri cu numele cheilor și firma și un număr cu prețul cheii.
Acum să definim transferul de date către SecondActivity. De exemplu, să definim următoarea interfață pentru MainActivity în fișierul activity_main.xml:
Aici sunt definite trei câmpuri de text pentru introducerea datelor și un buton.
În clasa MainActivity vom defini următorul conținut:
Pachetul 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; clasa publică MainActivity extinde AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = findView.Bid) .name); final EditText companyText = findViewById(R.id.company final EditText = findViewById(R.id.price); preţ = Integer.parseInt(priceText.getText().toString()); intent.putExtra("preț", preț startActivity(intent) )
În manipulatorul de clic pe butonul, primim datele introduse în câmpurile text EditText și le transmitem obiectului Intent folosind metoda putExtra(). Apoi lansăm SecondActivity.
Ca urmare, atunci când faceți clic pe butonul, se va lansa SecondActivity, care va primi unele date introduse în câmpurile de text.
Transferul de obiecte complexe
În exemplul de mai sus au fost transmise date simple - numere, șiruri. Dar putem transmite și date mai complexe. În acest caz, se utilizează mecanismul de serializare.
De exemplu, să presupunem că avem o clasă de produs definită în proiectul nostru:
Pachetul com.example.eugene.serializeapp; import java.io.Serializable; clasă publică Produsul implementează Serializabil (nume String privat; companie String privată; preț int privat; Produs public (nume șir, companie șir, preț int)( this.name = name; this.company = company; this.price = price; ) public String getName() ( return name; ) public void setName(String name) ( this.name = nume; ) public String getCompany() ( return company; ) public void setCompany(String company) ( this.company = company; ) public int getPrice() ( return price; ) public void setPrice(int price) ( this.price = price; ) )
Este de remarcat faptul că această clasă implementează interfața Serializable. Acum să schimbăm codul MainActivity:
Pachetul 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; clasa publică MainActivity extinde AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = findView.Bid) .name); final EditText companyText = findViewById(R.id.company final EditText = findViewById(R.id.price); price = Integer.parseInt(priceText.getText().toString() Product product = new Product(name, company, price Intent intent = new Intent(this, SecondActivity.class); .getSimpleName(), produs startActivity(intent));
Acum, în loc de trei date separate, este transmis un obiect produs. Cheia este rezultatul metodei Product.class.getSimpleName(), care returnează în esență numele clasei.
Și schimbați clasa SecondActivity:
Pachetul com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; clasa publică SecondActivity extinde AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16, 16, 16) ); Bundle arguments = getIntent().getExtras() final Product product if(arguments!=null)( product = (Product) arguments.getSerializable(Product.class.getSimpleName()); " + product.getName() + "\nCompanie: " + product.getCompany() + "\nPreț: " + String.valueOf(product.getPrice())); ) setContentView(textView); ) )
Metoda getSerializable() este folosită pentru a prelua datele deoarece clasa Product implementează interfața Serializable. În acest fel, putem trece un singur obiect în loc de o grămadă de date disparate.
O aplicație nu constă întotdeauna dintr-un singur ecran. De exemplu, am creat un program foarte util și utilizatorul dorește să știe cine este autorul acestuia. Face clic pe butonul „Despre program” și este dus la un nou ecran, unde există informații utile despre versiunea programului, autor, adresa site-ului web, câte pisici are autorul etc. Gândiți-vă la ecranul de activitate ca la o pagină web cu un link către o altă pagină. Dacă te uiți la codul din fișier MainActivity.java din lecțiile anterioare, veți vedea că clasa noastră Activitate principala se aplica si la Activitate(sau moștenitorii săi) sau, mai precis, moștenit de la el.
Clasa publică MainActivity extinde AppCompatActivity
După cum ați putea ghici, ar trebui să creăm o nouă clasă care ar putea fi similară cu Activitate principalași apoi cumva comutați la el când se apasă butonul.
Pentru experiment, vom lua programul de la prima lecție și vom folosi un buton pentru experimente (sau vom crea un nou proiect cu un singur buton pe ecran). Apoi, să creăm un formular nou pentru a afișa informații utile. De exemplu, să arătăm utilizatorului ce face o pisică când merge în stânga și în dreapta. De acord, aceasta este o informație foarte importantă care oferă cheia pentru dezlegarea Universului.
Vom crea o activitate nouă manual, deși studioul are șabloane gata făcute. Dar nu este nimic complicat acolo și pentru o mai bună înțelegere este util să faci totul manual.
Să creăm un nou fișier de marcare XML activity_about.xmlîn dosar res/aspect. Faceți clic dreapta pe folder aspectși selectați din meniul contextual Nou | Fișier cu resurse de aspect. Va apărea o casetă de dialog. În primul câmp, introduceți numele fișierului activitate_despre. În al doilea, trebuie să introduceți elementul rădăcină. Implicit este acolo ConstraintLayout. Ștergeți textul și introduceți ScrollView. Introducerea câtorva caractere este suficientă pentru ca studioul să sugereze opțiuni gata făcute, puteți apăsa imediat Enter fără să așteptați să fie introdus cuvântul complet:
Veți obține un spațiu liber corespunzător în care vom introduce elementul TextView.
Informațiile vor fi preluate din resurse, și anume resursa șir despre_text. Acum este evidențiat cu roșu, semnalând absența informațiilor. S-a putut apăsa Alt+Enterși introduceți text în caseta de dialog. Dar, pentru exemplul nostru, această metodă nu va funcționa, deoarece textul nostru va fi pe mai multe linii, folosind caractere de control. Deci hai să o facem altfel. Să deschidem fișierul res/values/strings.xmlși introduceți manual următorul text:
Am folosit cele mai simple etichete de formatare a textului HTML, cum ar fi , , . Pentru exemplul nostru, este suficient să evidențiem cu caractere aldine cuvintele care se referă la pisică și direcția de mișcare. Pentru a muta textul pe o linie nouă, utilizați simboluri \n. Să adăugăm o altă resursă șir pentru titlul noului ecran:
Ne-am dat seama de marcajele. În continuare, trebuie să creați o clasă pentru fereastră DespreActivity.java. Selectați din meniu Fișier | Nou | Clasa Javași completați câmpurile obligatorii. La început, este suficient să indicați doar numele. Apoi te vei ocupa de alte domenii.
Să luăm golul.
Acum clasa este aproape goală. Să adăugăm manual codul. Clasa trebuie să moștenească dintr-o clasă abstractă Activitate sau rudele lui ca FragmentActivity, AppCompatActivity etc. Să adăugăm extinde Activitatea. Clasa de activitate trebuie să aibă o metodă onCreate(). Plasați cursorul mouse-ului în interiorul clasei și selectați din meniu Cod | Metode de anulare(Ctrl+O). În caseta de dialog căutăm clasa necesară, puteți introduce primele caractere pe tastatură pentru o căutare rapidă. În metoda creată trebuie să apelați metoda setContentView(), care va încărca pe ecran marcajul pregătit. Vom avea această opțiune.
Pachetul ru.alexanderklimov.helloworld; import android.app.Activity; import android.os.Bundle; /** * Creat de Alexander Klimov la 12.01.2014. */ clasa publică AboutActivity extinde Activitatea ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Acum vine partea cea mai importantă. Sarcina noastră este să mergem la un nou ecran atunci când facem clic pe un buton de pe primul ecran. Să ne întoarcem la clasă Activitate principala. Să scriem un handler de clic pe buton:
Public void onClick (Vizualizare vizualizare) ( Intenție de intenție = intenție nouă (MainActivity.this, AboutActivity.class); startActivity(intent); )
Aici am folosit metoda de procesare a clicurilor pe buton descrisă în lecție.
Pentru a lansa un nou ecran, trebuie să creați o instanță a clasei Intențieși indicați clasa curentă în primul parametru și clasa la care să mergeți în al doilea, avem aceasta DespreActivitate. După aceasta, metoda este numită startActivity(), care lansează un nou ecran.
Dacă acum încercați să testați aplicația în emulator, veți primi un mesaj de eroare. Ce am greșit? Am ratat un pas important. Trebuie să înregistrați unul nou Activitateîn manifest AndroidManifest.xml. Găsiți acest fișier în proiectul dvs. și faceți dublu clic pe el. Se va deschide fereastra de editare a fișierului. Adăugați o nouă etichetă
Aici este utilă resursa șir despre_titlu. Lansăm aplicația, facem clic pe buton și obținem o fereastră Despre program. Astfel, am învățat cum să creăm o fereastră nouă și să o apelăm făcând clic pe un buton. Și avem la dispoziție un program mega-convenient - acum vom avea mereu la îndemână un indiciu despre ce face pisica când merge la stânga.
Încă o dată, rețineți că a doua clasă de activitate creată trebuie să moștenească din clasă Activitate sau altele similare ( ListActivity etc.), să aibă un fișier de markup XML (dacă este necesar) și să fie specificat în manifest.
După apelarea metodei startActivity() va începe o nouă activitate (în acest caz DespreActivitate), va deveni vizibil și se va muta în partea de sus a stivei care conține componentele care rulează. La apelarea unei metode finalizarea() dintr-o activitate nouă (sau când tasta de revenire hardware este apăsată) va fi închisă și scoasă din stivă. Dezvoltatorul poate naviga și la activitatea anterioară (sau la orice altă activitate) folosind aceeași metodă startActivity().
Crearea unui al treilea ecran - o metodă pentru leneși
Programatorii, ca și pisicile, sunt creaturi leneșe. Amintiți-vă întotdeauna că pentru o activitate trebuie să creați un marcaj și o clasă de la care moștenește Activitate, și apoi nu uitați să înregistrați clasa în manifest - ei bine.
În acest caz, selectați din meniu Fișier | Nou | Activitate | Activitate de bază(sau alt șablon). În continuare, va apărea fereastra familiară pentru crearea unei noi activități. Completați câmpurile obligatorii.
Faceți clic pe butonul finalizarea iar activitatea va fi gata. Pentru a verifica acest lucru, deschideți fișierul manifest și verificați dacă există o nouă intrare. Nici măcar nu vorbesc despre fișierele de clasă și de marcare, acestea vor apărea singure în fața ta.
Adăugați un buton nou pe ecranul principal de activitate și scrieți codul pentru a comuta la activitatea creată.
La început, v-aș sfătui să creați manual toate componentele necesare pentru noua activitate, astfel încât să înțelegeți relația dintre clasă, markup și manifest. Și când înțelegi, poți folosi Expertul de creare a activității pentru a-ți accelera munca.
Transmiterea datelor între activități
Am folosit un exemplu simplu pentru a apela un alt ecran de activitate. Uneori nu trebuie doar să apelați un nou ecran, ci și să transferați date pe acesta. De exemplu, numele de utilizator. În acest caz, trebuie să utilizați o zonă specială extraData, pe care o are clasa Intenție.
Regiune extraData este o listă de perechi valoare cheie, care se transmite odata cu intentia. Șirurile sunt folosite ca chei și orice tipuri de date primitive, matrice de primitive, obiecte de clasă pot fi folosite pentru valori Pachet si etc.
Pentru a transfera date către o altă activitate, utilizați metoda puneExtra():
Intent.putExtra ("Cheie", "Valoare");
Activitatea de recepție trebuie să apeleze la o metodă adecvată: getIntExtra(), getStringExtra() etc.:
Int count = getIntent().getIntExtra("nume", 0);
Să refacem exemplul anterior. Avem deja trei activități. Prima activitate va avea două câmpuri de text și un buton. Aspectul poate fi după cum urmează:
La a doua activitate A doua activitate setați elementul TextView, în care vom afișa textul primit de la prima activitate. Să scriem următorul cod pentru metodă onCreate() la a doua activitate.
@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = „Animal”; String gift = „goașă”; TextView infoTextView = (TextView)findViewBy .id.textViewInfo); infoTextView.setText(user + ", vi s-a dat " + cadou);
Dacă acum rulăm programul și pur și simplu deschidem a doua fereastră, așa cum a fost descris în prima parte a articolului, atunci vom vedea inscripția implicită Animal, ți-au dat o gaură pentru gogoși. De acord, este destul de enervant să primești astfel de mesaje.
Să corectăm situația. Adăugați codul la prima activitate:
Public void onClick (Vizualizare vizualizare) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Intent = new Intent(s, MainActivity.this). class); // împinge textul din primul câmp de text în cheia numelui de utilizator intent.putExtra ("username", userEditText.getText().toString()); intent.putExtra("cadou" ", giftEditText.getText().toString()); startActivity(intent); )
Am așezat obiectul într-un recipient special Intenție două chei cu valori care sunt preluate din câmpurile de text. Când utilizatorul introduce date în câmpurile de text, acestea vor intra în acest container și vor fi trecute la a doua activitate.
A doua activitate ar trebui să fie pregătită pentru a primi mesaje cu căldură după cum urmează (în aldine).
// Valori implicite String user = "Animal"; String gift = „găuri pentru gogoși”; utilizator = getIntent().getExtras().getString(„nume utilizator”); cadou = getIntent().getExtras().getString("cadou"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , vi s-a oferit " + cadou);
Acum mesajul pare mai puțin ofensator și chiar plăcut pentru unii. În exemplele complexe, este recomandabil să adăugați o verificare la prelucrarea datelor. Pot exista situații în care lansați o a doua activitate cu date goale de tip nul, ceea ce poate cauza blocarea aplicației.
În cazul nostru, știm că ne așteptăm la o valoare șir, așa că codul poate fi rescris astfel:
Intenție de intenție = getIntent(); utilizator = intent.getStringExtra ("nume utilizator");
Utilizator = getIntent().getStringExtra("nume utilizator");
Programul are un dezavantaj - nu este clar de la cine primim salutări. Orice maimuță bine crescută nu va accepta un cadou dintr-o sursă anonimă. Deci, ca teme, adăugați un alt câmp de text pentru a introduce numele utilizatorului care trimite mesajul.
Google recomandă utilizarea următorului format pentru chei: numele pachetului dvs. ca prefix, urmat de cheia însăși. În acest caz, puteți fi sigur de unicitatea cheii atunci când interacționați cu alte aplicații. Ceva de genul:
Public final static String USER = "ru.alexanderklimov.myapp.USER";
Cine a înrămat pisica Vaska - obținem rezultatul înapoi
Nu este întotdeauna suficient să transmiteți pur și simplu date unei alte activități. Uneori, atunci când este închisă, trebuie să obțineți informații din altă activitate. Dacă mai devreme am folosit metoda startActivity (intenție de intenție), atunci există o metodă înrudită startActivityForResult(intenție de intenție, int RequestCode). Diferența dintre metode este parametrul suplimentar RequestCode. Practic, este doar un număr întreg pe care îl poți găsi singur. Este necesar pentru a distinge de la cine a venit rezultatul. Să presupunem că aveți cinci ecrane suplimentare și le atribuiți valori de la 1 la 5, iar folosind acest cod puteți determina al cui rezultat trebuie să procesați. Puteți folosi valoarea -1, atunci va fi la fel cu apelarea metodei startActivity(), adică nu vom obține niciun rezultat.
Dacă utilizați metoda startActivityForResult(), atunci trebuie să înlocuiți metoda din codul dvs. pentru a primi rezultatul onActivityResult()și procesează rezultatul. Confuz? Să ne uităm la un exemplu.
Să presupunem că ești detectiv. S-au primit informații că două bucăți de cârnați și alte produse au fost furate de pe masa unei persoane influente dintr-un restaurant. Suspiciunea a căzut asupra a trei suspecți - o cioară, un nenorocit de câine și pisica Vaska.
Unul dintre vizitatori a oferit o serie de fotografii de pe iPhone-ul său de prezentare:
Există și mărturie de la un alt martor: Iar Vaska ascultă și mănâncă.
Creați un nou proiect Sherlock cu două activități. Pe primul ecran va apărea un buton pentru a trece la al doilea ecran și o etichetă text în care va fi afișat numele hoțului.
Pe al doilea ecran va apărea un grup de comutatoare:
Deoarece ne vom aștepta la un răspuns de la al doilea ecran, trebuie să folosim metoda startActivityForResult() pe primul ecran în care vom trece variabila CHOOSE_THIEF ca parametru RequestCode.
Static final privat int CHOOSE_THIEF = 0; public void onClick (Vizualizare v) ( Intenție questionIntent = new Intent (MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Uită-te la cod. Când facem clic pe butonul vom lucra cu al doilea ecran Alegeți Activitateși lansați al doilea ecran în așteptarea rezultatului.
Să mergem la al doilea ecran și să scriem codul pentru a doua activitate.
Public final static String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(Vizualizare v) ( Intenție answerIntent = new Intent(); comutați (v.getId()) (case R.id.radioDog: answerIntent.putExtra(THIEF, „La naiba de câine”); break; case R.id .radioCrow: answerIntent.putExtra(THIEF, „Crow”; ;
Totul este simplu aici, când detectivul alege numele criminalului, apoi prin metoda puneExtra() trecem numele cheii și valoarea acesteia.
Pentru comoditate, după selectare, închidem imediat a doua fereastră și înainte de a închide trecem valoarea RESULT_OK, astfel încât să fie clar că alegerea a fost făcută. Dacă utilizatorul închide ecranul prin butonul Înapoi, valoarea va fi transmisă RESULT_CANCELED.
Metodă setResult() ia doi parametri: codul rezultat și rezultatul însuși, reprezentat ca o intenție. Codul rezultat vă spune cu ce rezultat a finalizat activitatea, de regulă, acesta este fie Activitate.RESULT_OK, sau Activitate.RESULT_CANCELED. În unele cazuri, trebuie să utilizați propriul cod de returnare pentru a gestiona variațiile specifice aplicației dvs. Metodă setResult() acceptă orice valoare întreagă.
Dacă veți transmite date în mod explicit printr-un buton, atunci ar fi o idee bună să adăugați o metodă finalizarea() pentru a închide a doua activitate ca fiind inutilă. Dacă tranziția are loc prin butonul Înapoi, atunci acest lucru nu este necesar.
Dacă activitatea a fost închisă de utilizator prin apăsarea butonului de revenire hardware sau dacă metoda finalizarea() a fost numit înainte de metodă setResult(), codul rezultat va fi setat la RESULT_CANCELED, iar intenția returnată va afișa valoarea nul.
Revenim la primul ecran. Primul ecran așteaptă un răspuns de la al doilea ecran, așa că trebuie să adăugați o metodă la cod onActivityResult().
@Override protected void onActivityResult(int requestCode, int resultCode, date Intent) ( super.onActivityResult(requestCode, resultCode, date); 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(""); // șterge textul ) ) )
Metoda așteaptă date primite cu cod CHOOSE_THIEF, iar dacă sosesc astfel de date, preia valoarea de la cheie AlegeActivity.THIEF folosind metoda getStringExtra. Afișăm valoarea rezultată în TextView(variabil infoTextView). Dacă ne-am întors la ecran prin butonul Înapoi, atunci pur și simplu ștergem textul.
Când o activitate copil este închisă în interiorul componentei părinte, este declanșat un handler onActivityResult(). Handler onActivityResult() acceptă mai mulți parametri.
- Solicitați codul. Cod folosit pentru a începe activitatea care returnează rezultatul
- Codul rezultat. Un cod de rezultat stabilit de activitatea copilului care indică modul în care s-a finalizat activitatea sa. Aceasta poate fi orice valoare întreagă, dar de obicei oricare Activitate.RESULT_OK, sau Activitate.RESULT_CANCELED
- Date. Intenția utilizată pentru a împacheta datele returnate. În funcție de scopul activității copilului, aceasta poate include o cale URI care reprezintă piesa de conținut selectată. Alternativ (sau complementar), activitatea copilului poate returna informații sub formă de valori simple împachetate într-un parametru de intenție in plus
Dacă o activitate de copil sa încheiat în mod neașteptat sau dacă nu a fost specificat niciun cod de rezultat înainte de a o închide, acest parametru va deveni Activitate.RESULT_CANCELED.
Lansăm proiectul, facem clic pe butonul și mergem la al doilea ecran. Acolo selectăm una dintre opțiuni. Dacă selectezi cioara, ecranul se va închide și numele criminalului va apărea pe primul ecran. Dacă selectați un câine, numele acestuia va fi afișat.
Apropo, dacă selectați o pisică, numele acesteia nu va fi afișat! Verificați-l și vedeți singur. Vei întreba de ce? Primar Watson! Infractorul nu a ținut cont de un detaliu important. Restaurantul era supravegheat de camere video, iar înregistrarea arăta cine a furat de fapt cârnatul și a înrămat pisica. Vaska, stai!
P.S. Dacă la început ceva părea neclar, atunci cu practică multe vor deveni mai clare. Transferul de date între ecrane este obișnuit în aplicații și veți studia exemplul de mai multe ori.
P.P.S. Cel mai bun pește este cârnații. Cunoscând această slăbiciune, nu a fost greu să încadrezi pisica.
Folosind filtre
În articol am arătat o modalitate obișnuită de a trece la o altă activitate atunci când sunteți în metodă startActivity() sunt indicate clasa curentă și clasa de transferat. Apropo, clasa de activitate nu trebuie să facă parte din aplicația dvs. Dacă știți numele clasei dintr-o altă aplicație, puteți trece la el. Dar poți trece la o altă activitate în alt mod.
În practică, este mai puțin obișnuit, dar poate fi util. Să presupunem că aveți deja o a doua activitate. În manifest îi vom adăuga un filtru special:
Și lansăm a doua activitate făcând clic pe un buton în acest fel.
Public void onClick (Vizualizare vizualizare) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity")); )
Să înlocuim șirul lung cu o constantă.
Public static final String ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick (Vizualizare vizualizare) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Deci ce am făcut. Pentru a doua activitate, am înregistrat un filtru și am specificat un nume pentru acțiuneîn atribut android:nume. Pentru comoditate, am pus doar numele complet al activității cu numele pachetului în ea. Constructor de clasă Intenție are mai multe versiuni supraîncărcate. Într-o versiune, puteți specifica un șir pentru acțiune. Am indicat acțiunea noastră creată, care este înregistrată în a doua activitate. În timpul funcționării, sistemul vizualizează manifestele tuturor aplicațiilor instalate. Când caută o potrivire, sistemul găsește filtrul nostru și lansează activitatea necesară.
Puteți lansa alte activități folosind același principiu. Uita-te la exemplu. Dacă copiați exemplul pentru dvs. și vă uitați la documentația pentru android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, veți vedea că acest cod corespunde unei constante șir public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = „android.settings.AIRPLANE_MODE_SETTINGS”. Comparați cu codul nostru. Puteți presupune că activitatea de setări pentru modul offline are această linie în filtrul său.
Filtrați numele categoriei android.intent.category.DEFAULT spune sistemului să efectueze acțiunea implicită, care este să înceapă activitatea. Mai sunt si alte nume care nu ne intereseaza inca.
Și acum o ultimă întrebare. Ce se întâmplă dacă creați o altă activitate și specificați același filtru ca a doua activitate? Hai să verificăm. Creați o a treia activitate și copiați blocul cu filtrul din a doua activitate în el.
Faceți clic pe butonul din prima activitate. Sistemul vă va cere să selectați opțiunea dorită.
Dacă selectați MEREU, apoi data viitoare nu va trebui să alegeți. Pentru a reseta selecția, accesați proprietățile aplicației din Setări și găsiți butonul Ștergeți setările implicite.
Lansați o activitate după numele acesteia
În constructor Intenție al doilea parametru este clasa. Dar să presupunem că există un fel de bază de date în care sunt indicate numele activităților și trebuie să lansăm activitatea dorită după numele acesteia. Putem obține clasa în sine pe baza unei variabile șir și lansăm activitatea.
Încercați ( // Numele complet al clasei de activitate String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // obțineți obiectul Class>myClass = Class.forName(activityName); Intent intent = new Intent(this, myClass); startActivity(intentie); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
Cumva aveam sarcina de a transfera date de la un serviciu la o activitate. Căutarea a început pentru o soluție în SDK-ul standard, dar din moment ce nu era timp, am creat o soluție proastă sub forma utilizării unei baze de date. Dar întrebarea era deschisă și după ceva timp mi-am dat seama de o metodă mai corectă, care se află în SDK - folosind clasele Message, Handler, Messenger.
Idee
Trebuie să transferăm date de la activitate la serviciu și înapoi. Cum facem asta? Avem deja tot ce ne trebuie pentru a ne rezolva problema. Tot ce aveți nevoie este să legați serviciul de activitate folosind bindService, să treceți parametrii necesari și puțină magie sub forma utilizării claselor Message. Și magia este să folosiți variabilele de instanță Message și, în special, replyTo. Avem nevoie de această variabilă pentru a putea accesa instanța serviciului Messanger din activitate și în serviciu instanța Messanger a activității. De fapt, nu este atât de simplu. Cel puțin pentru mintea mea mai puțin talentată. În parte, doar îmbunătățesc documentația care există deja - Servicii De asemenea, există un exemplu bun pe StackOverflow. In orice caz, sper ca articolul sa fie de folos macar cuiva si munca mea nu a fost in zadar.
Exemplu
De exemplu, vom implementa un serviciu care va crește și scade valoarea contorului și va returna rezultatul în activitate, în TextView. Voi omite codul de aspect, deoarece există două butoane și un câmp de text - totul este simplu.
Implementarea
Iată codul complet de activare:
Clasa publică MainActivity extinde Activitatea (public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final Messenger messenger = new Messenger(new IncomingHandler()); Messenger toServiceMessenger; @Override public void onCreate(Bundle savedInstance.State) onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt); .BIND_AUTO_CREATE); ) @Override public void onDestroy())( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(Buton View)( Message msg = Message.obtain(null, TestService.COUNT_PLUS); msg. replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(Buton View)( Message msg = Message.obtain(null, TestService.COUNT_MINUS); msg .replyTo = mesager; încercați ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) clasă privată IncomingHandler extinde Handler ( @Override public void handleMessage(Message msg)( switch (msg.what) (caz TestService. GET_COUNT: Log.d(TAG, "(activity)...get count"(""+msg.arg1 ) ) private class TestServiceConnection implementează ServiceConnection ( @Override public void(ComponentName)); nume, serviciu IBinder) ( toServiceMessenger = new Messenger(serviciu); //trimite valoarea inițială a contorului Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = messenger; msg.arg1 = 0; / /contorul nostru încercați ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(NumeNume Componentă) ( ) ) )
Lasă-mă să explic. La crearea unei activități, ne legăm imediat de serviciu, implementând interfața ServiceConnection și în aceasta trimitem un mesaj către serviciul „set the counter value”, trecând zero și creând un toServiceMessanger, pasând interfața IBinder constructorului. Apropo, această copie trebuie returnată la service, altfel va exista un NPE. Folosind această clasă trimitem mesaje către serviciu. Și aici este magia - în variabila replyTo salvăm cealaltă instanță a noastră Messenger - cea care primește un răspuns de la server și prin aceasta se va realiza comunicarea cu activitatea.
Pentru a primi un mesaj de la serviciu, folosim Handler-ul nostru și pur și simplu căutăm variabilele de care avem nevoie și luăm acțiuni asupra lor. Făcând clic pe butoanele (metode countIncrClick, countDecrClick), trimitem solicitări către serviciu, indicând acțiunea dorită în variabila msg.what.
Pachetul com.example.servicetest; import android.app.Service; import android.content.*; import android.os.*; import android.os.Process; import android.util.Log; clasă publică TestService extinde Serviciul ( 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 mesager; Messenger toActivityMessenger; @Override public void onCreate())( super.onCreate(); thread HandlerThread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread()); 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; ) //message clasa privată de activitate a handlerului IncomingHandler extinde Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Message msg)( //super.handleMessage(msg); toActivityMessenger = msg.replyTo; comutați (msg.what) (case SET_COUNT: count = msg.arg1; Log.d(MainActivity.TAG, „(serviciu)...set count”); break; case COUNT_PLUS: count++; Log.d(MainActivity.TAG , "(service)...count plus"); caz COUNT_MINUS: Log.d(MainActivity.TAG, "(service)...count minus"; ); outMsg.arg1 = număr; outMsg.replyTo = mesager; încercați ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) ) )
Totul este similar cu logica din Activiti. Nici nu știu dacă trebuie să explic ceva. Singurul punct este că trimit imediat cererea înapoi la activitatea din handleMessage, folosind variabila magic replyTo și scoțând Messenger-ul dorit de mai sus. Și al doilea punct despre care am vorbit deja este:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
fără de care totul va cădea. Această instanță de interfață va fi transmisă la ServiceConnection
Concluzie
În întregime. Acesta este un exemplu exagerat de interacțiune între o activitate și un serviciu. Mi se pare că aceasta este o interacțiune destul de netrivială, deși alții ar putea gândi altfel.
Întrebări, precizări etc. în PM. Pot exista inexactități cu privire la unele aspecte, așa că nu ezitați să scrieți și să corectați.
Sper că postarea a fost utilă cititorilor.