Rakendus ei koosne alati ühest ekraanist. Näiteks oleme loonud väga kasulik programm ja kasutaja soovib teada, kes on autor. Ta klõpsab nuppu "Teave" ja avaneb uuele ekraanile, kus on kasulikku teavet programmi versiooni, autori, saidi aadressi, autori kasside jne kohta. Mõelge tegevuskuvale kui veebilehele, millel on link teisele lehele. Kui vaatate failis olevat koodi MainActivity.java eelmistest tundidest näete, et meie klass Põhitegevus kehtib ka kohta Tegevus(või tema pärijad) või, täpsemalt öeldes, on päritud temalt.
Avalik klass MainActivity laiendab rakendust AppCompatActivity
Nagu võite arvata, peaksime looma uue klassi, mis võib välja näha Põhitegevus ja siis lülituda sellele nupuvajutusega kuidagi.
Katse jaoks võtame programmi esimesest õppetunnist ja kasutame nuppu katsete tegemiseks (või loo uus projektühe nupuga ekraanil). Järgmiseks loome uus vorm kuvada kasulik informatsioon. Näiteks näitame kasutajale, mida kass teeb, kui ta läheb vasakule ja paremale. Nõus, see on väga oluline teave, mis annab võtme universumi lahtiharutamiseks.
Loome uue tegevuse käsitsi, kuigi stuudiol on valmis mallid. Kuid midagi keerulist pole ja paremaks mõistmiseks on kasulik kõike käsitsi teha.
Loome uue XML-märgistusfaili action_about.xml kaustas res/paigutus. Paremklõpsake kaustal paigutus ja valida kontekstimenüü Uus | Paigutusressursi fail. Ilmub dialoogiboks. Sisestage esimesele väljale faili nimi tegevus_umbes. Teises peate sisestama juurelemendi. Vaikimisi on see olemas PiirangLayout. Kustuta tekst ja sisesta kerimisvaade. Mõne tähemärgi sisestamisest piisab, et stuudio pakuks valmis valikuid, võite kohe vajutada sisestusklahvi, ootamata sõna täielikku sisestamist:
Saame vastava tooriku, millesse sisestame elemendi tekstivaade.
Teave hangitakse ressurssidest, nimelt stringressursist about_text. Nüüd on see punasega esile tõstetud, mis annab märku teabe puudumisest. sai vajutada Alt+Enter ja sisestage dialoogiboksi tekst. Kuid meie näite puhul see meetod ei tööta, kuna meie tekst on mitmerealine, kasutades juhtmärke. Nii et teeme seda teisiti. Avame faili res/values/strings.xml ja sisestage käsitsi järgmine tekst:
Kasutasime lihtsaimaid HTML-i tekstivormingu silte nagu , , . Meie näite puhul piisab kassile ja liikumissuunale viitavatest sõnadest paksus kirjas. Teksti tõlkimiseks keelde uus rida kasutada sümboleid \n. Lisame uue ekraani pealkirja jaoks veel ühe stringiallika:
Märgistamisega mõistetav. Järgmiseks peate akna jaoks looma klassi AboutActivity.java. Valige menüüst fail | Uus | Java klass ja täitke nõutud väljad. Algul piisab ainult nime määramisest. Seejärel tegele teiste valdkondadega.
Teeme ettevalmistusi.
Nüüd on klassiruum peaaegu tühi. Lisame koodi käsitsi. Klass peab pärima abstraktsest klassist Tegevus või selle sugulased FragmentActivity, AppCompatActivity jne. Lisamine pikendab tegevust. Tegevusklassil peab olema meetod onCreate(). Viige hiirekursor klassi sisse ja valige menüüst kood | Alista meetodid(Ctrl+O). Otsime dialoogiboksis soovitud klassi, mille jaoks saate klaviatuuril tippida esimesed märgid kiire otsing. Loodud meetodis peate meetodi välja kutsuma setContentView(), mis laadib ekraanile ettevalmistatud märgistuse. Meil on selline variant.
Pakett et.alexanderklimov.helloworld; import android.app.Activity; import android.os.Bundle; /** * Loodud Aleksander Klimovi poolt 12.01.2014. */ avalik klass AboutActivity laiendab tegevust ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Nüüd algab kõige tähtsam. Meie ülesanne on liikuda uuele ekraanile, kui esimesel ekraanil klõpsate nuppu. Lähme tagasi klassi Põhitegevus. Kirjutame nupu kliki töötleja:
Public void onClick(vaatevaade) ( Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Siin kasutasin tunnis kirjeldatud nupuklõpsude käsitlemise meetodit.
Uue ekraani käivitamiseks peate looma klassi eksemplari Kavatsus ja määrake esimeses parameetris praegune klass ja teises parameetris ülemineku klass, meil on see Teave tegevuse kohta. Pärast seda nimetatakse meetodit startActivity(), mis käivitab uue ekraani.
Kui proovite nüüd rakendust emulaatoris testida, kuvatakse tõrketeade. Mida me valesti tegime? Meil jäi üks oluline samm vahele. Peate registreerima uue Tegevus manifestis AndroidManifest.xml. Leidke see fail oma projektist ja topeltklõpsake seda. Avaneb faili redigeerimise aken. Lisage uus silt
Siin tuleb appi stringiressurss about_title. Käivitage rakendus, klõpsake nuppu ja avage aken Programmi kohta. Nii õppisime, kuidas luua uus aken ja seda nupuvajutusega kutsuda. Ja meie käsutusse on ilmunud mega mugav programm - nüüd on alati käepärast vihje, mida kass teeb, kui ta vasakule läheb.
Taaskord juhin tähelepanu asjaolule, et teine loodud tegevusklass peab olema klassist päritud Tegevus või sarnane ( Loenditegevus jne), omama XML-märgistusfaili (vajadusel) ja olema kirjutatud manifestis.
Pärast meetodi helistamist startActivity() algab uus tegevus (antud juhul Teave tegevuse kohta), muutub see nähtavaks ja liigub jooksvaid komponente sisaldava virna ülaossa. Meetodi kutsumisel lõpetama() uuest tegevusest (või riistvaralise tagasilükkeklahvi vajutamisel) see suletakse ja eemaldatakse virust. Arendaja saab sama meetodit kasutades navigeerida ka eelmisele (või mõnele muule) tegevusele startActivity().
Kolmanda ekraani loomine – viis laiskadele
Programmeerijad, nagu kassid, on laisad olendid. Pidage alati meeles, et tegevuse jaoks peate looma märgistuse ja klassi, mis pärineb Tegevus, ja siis ärge unustage klassi manifestis registreerida – oh noh, mida kuradit.
Sel juhul valige menüüst fail | Uus | tegevus | põhitegevus(või muu muster). Järgmisena ilmub tuttav aken uue tegevuse loomiseks. Täitke nõutud väljad.
Klõpsake nuppu Lõpetama ja tegevus on valmis. Selle kontrollimiseks avage manifesti fail ja kontrollige uut kirjet. Ma ei räägi klassifailidest ja märgistustest, need ilmuvad teie ette.
Lisage ise põhitegevuse ekraanile uus nupp ja kirjutage loodud tegevuse juurde navigeerimiseks kood.
Algul soovitaksin kõik uue tegevuse jaoks vajalikud komponendid käsitsi luua, et mõista klassi, märgistuse ja manifesti seost. Ja kui olete selle kätte saanud, saate tegevuste kiirendamiseks kasutada tegevuste loomise viisardit.
Andmete edastamine tegevuste vahel
Kasutasime kõige lihtsamat näidet mõne teise tegevuskuva kutsumiseks. Mõnikord on vaja mitte ainult uuele ekraanile helistada, vaid ka sellele andmeid edastada. Näiteks kasutajanimi. Sel juhul peate kasutama spetsiaalset ala lisaandmed, mis klassis on Kavatsus.
Piirkond lisaandmed on paaride loend võti/väärtus, mis edastatakse koos kavatsusega. Stringe kasutatakse võtmetena ja väärtuste jaoks saate kasutada mis tahes primitiivseid andmetüüpe, primitiivide massiive, klassi objekte kimp ja jne.
Andmete edastamiseks teisele tegevusele kasutage meetodit paneExtra():
Intent.putExtra("Võti", "Väärtus");
Vastuvõttev tegevus peaks kutsuma mõnda sobivat meetodit: getIntExtra(), getStringExtra() jne.:
Int count = getIntent().getIntExtra("nimi", 0);
Teeme eelmise näite uuesti. Meil on juba kolm tegevust. Esimesel tegevusel on kaks tekstivälja ja nupp. Välimus võib olla järgmine:
Teisel tegevusel Teine tegevus seadke element tekstivaade, milles kuvame esimesest tegevusest saadud teksti. Kirjutame meetodi jaoks järgmise koodi onCreate() teisel tegevusel.
@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String gift = "sõõriku auk"; TextView infoTextView = (TextView)Id(RBy .id.textViewInfo); infoTextView.setText(kasutaja + " , teile anti " + kingitus); )
Kui käivitame nüüd programmi ja kutsume lihtsalt teise akna välja, nagu on kirjeldatud artikli esimeses osas, näeme vaikekirja ZhYvotnoe, sulle anti sõõriku auk. Nõus, selliseid sõnumeid on üsna kahju saada.
Parandame olukorra. Lisage kood esimesele tegevusele:
Public void onClick(View view) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (R.id.editTextGift); FindViewById(R.id.editTextGift); Intent.intentMa =in IntentthintentMa =intent.intent.isActivity. klass); // lükake teksti esimeselt tekstiväljalt kasutajanime võtmesse intent.putExtra("kasutajanimi", userEditText.getText().toString()); // lükake tekst teiselt tekstiväljalt kingivõtmesse intent.putExtra("kingitus", kingitusEditText.getText().toString()); startActivity(intent); )
Panime spetsiaalsesse objekti konteinerisse Kavatsus kaks klahvi tekstiväljadelt võetud väärtustega. Kui kasutaja sisestab andmed tekstiväljadele, satuvad need sellesse konteinerisse ja edastatakse teisele tegevusele.
Teine tegevus peaks olema valmis sõnumeid soojalt vastu võtma järgmiselt (rasvas kirjas esile tõstetud).
// Vaikeväärtused String user = "LIFE"; String kingitus = "sõõriku auk"; kasutaja = getIntent().getExtras().getString("kasutajanimi"); kingitus = getIntent().getExtras().getString("kingitus"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(kasutaja + " , teile anti " + kingitus);
Nüüd ei tundu sõnum nii solvav, vaid mõne jaoks isegi meeldiv. Keerukate näidete puhul on soovitav andmetöötluse käigus lisada valideerimine. On olukordi, kui alustate teist tegevust tühjade andmetega, näiteks null, mis võib rakenduse krahhi.
Meie puhul teame, et ootame stringi väärtust, nii et koodi saab ümber kirjutada järgmiselt:
intent intent = getIntent(); kasutaja = intent.getStringExtra("kasutajanimi");
Kasutaja = getIntent().getStringExtra("kasutajanimi");
Programmil on puudus - pole selge, kellelt me tervitusi saame. Ükski hästi käituv ahv ei võta anonüümselt allikalt kingitust vastu. Seega lisage kodutöö jaoks veel üks tekstiväli, et sisestada sõnumi saatva kasutaja nimi.
Google soovitab kasutada võtmete jaoks järgmist vormingut: eesliitena teie paketi nimi, millele järgneb võti ise. Sel juhul võite olla kindel, et võti on teiste rakendustega suhtlemisel unikaalne. Umbes nii:
Avalik lõplik staatiline string KASUTAJA = "ru.alexanderklimov.myapp.USER";
Kes kass Vaska raamis - saame tulemuse tagasi
Alati ei piisa lihtsalt andmete edastamisest teisele tegevusele. Mõnikord peate mõne muu tegevuse kohta teavet tagasi saama, kui see on suletud. Kui enne kasutasime meetodit startActivity (Intent intent), siis on olemas seotud meetod startActivityForResult(Intent intent, int RequestCode). Meetodite erinevus seisneb lisaparameetris päringu kood. Põhimõtteliselt on see vaid täisarv, mida saate enda kohta mõelda. See on vajalik selleks, et eristada, kellelt tulemus tuli. Oletame, et teil on viis lisaekraani ja määrate neile väärtused vahemikus 1 kuni 5 ning selle koodi järgi saate määrata, kelle tulemust peate töötlema. Võite kasutada väärtust -1, siis on see samaväärne meetodi kutsumisega startActivity(), st. me ei saa mingit tulemust.
Kui kasutate meetodit startActivityForResult(), siis peate tulemuse saamiseks koodis oleva meetodi alistama onActivityResult() ja töödelda tulemust. Segaduses? Vaatame näidet.
Oletame, et olete detektiiv. Laekus info, et restoranis varastati mõjuka isiku laualt kaks tükki vorsti ja muid tooteid. Kahtlus langes kolmele kahtlusalusele - varesele, kuradi koerale ja kassile Vaskale.
Üks külastajatest esitas fotoseeria oma pontoonist iPhone'ist:
Samuti on olemas teise tunnistaja ütlused: Ja Vaska kuulab ja sööb.
Loome uue projekti Sherlock kahe tegevusega. Esimesel ekraanil on nupp teisele ekraanile lülitumiseks ja tekstisilt, mis kuvab varga nime.
Teisel ekraanil on raadionuppude rühm:
Kuna ootame vastust teiselt ekraanilt, peame kasutama meetodit startActivityForResult() esimesel ekraanil, kus muutuja edastame CHOOSE_HIEF parameetrina päringu kood.
staatiline lõplik privaatne int VALI_VARAS = 0; public void onClick(Vaata v) ( Intent questionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(question Intent, CHOOSE_HIEF); )
Vaata koodi. Kui nuppu klõpsate, hakkame töötama teise ekraaniga Valige Aktiivsus ja käivitage teine ekraan, mis ootab tulemust.
Liigume teisele ekraanile ja kirjutame teise tegevuse koodi.
Avalik lõplik staatiline String THIEF = "ru.alexanderklimov.sherlock.HIEF"; public void onRadioClick(View v) ( Intent answer Intent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Kuradi koer"); break; case R.id .radioCrow: vastusIntent.putExtra(THIEF, "Crow"); murda; kääne ();)
Siin on kõik lihtne, kui detektiiv valib kurjategija nime, siis meetodi kaudu paneExtra() edastame võtme nime ja selle väärtuse.
Mugavuse huvides sulgeme pärast valimist kohe teise akna ja edastame väärtuse enne sulgemist RESULT_OK teha selgeks, et valik on tehtud. Kui kasutaja sulgeb ekraani nupu Tagasi, edastatakse väärtus RESULT_CANCELED.
meetod setResult() võtab kaks parameetrit: saadud kood ja tulemus ise, mis on esitatud eesmärgina. Saadud kood ütleb, millise tulemusega tegevus lõppes, reeglina on see kas Tegevus.RESULT_OK, või Tegevus.RESULT_CANCELED. Mõnel juhul peate rakendusepõhiste valikute käsitlemiseks kasutama oma tagastuskoodi. meetod setResult() toetab mis tahes täisarvu väärtust.
Kui edastate andmed selgesõnaliselt nupu kaudu, oleks tore lisada meetod lõpetama() sulgeda teine tegevus kui mittevajalik. Kui üleminek toimub nupu Tagasi kaudu, pole see vajalik.
Kui kasutaja sulges tegevuse riistvara tagasinupu vajutamisel või kui meetod lõpetama() kutsuti enne meetodit setResult(), määratakse tulemuseks kood RESULT_CANCELED ja tagastatud kavatsus näitab väärtust null.
Pöördume tagasi esimesele ekraanile. Esimene ekraan ootab vastust teiselt ekraanilt, seega peate koodile meetodi lisama onActivityResult().
@Alista kaitstud void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == CHOOSE) (_T) if (resultCode == RESULT_OK) ( String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // kustuta tekst ) ) )
Meetod ootab sissetulevaid andmeid koodiga CHOOSE_HIEF, ja kui sellised andmed saabuvad, eraldab võtmest väärtuse Valige Aktiivsus.VARKAS meetodit kasutades getStringExtra. Väljastame saadud väärtuse väärtusele tekstivaade(muutuja infoTextView). Kui naasime ekraanile tagasi nupu kaudu, kustutame teksti lihtsalt.
Kui alamtegevus suletakse põhikomponendi sees, käitleb käitleja onActivityResult(). Käitleja onActivityResult() võtab mitu parameetrit.
- Küsi koodi. Kood, mida kasutatakse tulemuse tagastava tegevuse käivitamiseks
- Saadud kood. Lapse tegevuse poolt määratud tulemuse kood, mis näitab, kuidas lapse tegevus lõppes. See võib olla mis tahes täisarv, kuid tavaliselt kumbki Tegevus.RESULT_OK, või Tegevus.RESULT_CANCELED
- Andmed. Tagastatud andmete pakkimise eesmärk. Olenevalt alamtegevuse eesmärgist võib see sisaldada URI teed, mis esindab valitud sisu. Teise võimalusena (või lisaks) võib lapse tegevus tagastada teabe lihtsate väärtustena, mis on mähitud kavatsusparameetrisse lisad
Kui alamtegevus lõppes ootamatult või kui tulemuskoodi ei määratud enne selle sulgemist, muutub see parameeter võrdseks Tegevus.RESULT_CANCELED.
Alustame projekti, klõpsame nuppu ja läheme teisele ekraanile. Seal valime ühe valikutest. Kui valite varese, siis ekraan sulgub ja esimesel ekraanil kuvatakse kurjategija nimi. Kui valite koera, kuvatakse tema nimi.
Muide, kui valite kassi, siis tema nime ei kuvata! Kontrollige ja veenduge ise. Te küsite, miks? Elementaarne Watson! Kurjategija ei arvestanud ühe olulise detailiga. Restoran oli videokaamerate jälgimise all ning salvestiselt oli näha, kes tegelikult vorsti varastas ja kassi raamis. Vaska, pea vastu!
P.S. Kui alguses tundus miski arusaamatu, siis harjutades selgub palju. Andmete edastamine ekraanide vahel on rakendustes tavaline ja te uurite näidet rohkem kui üks kord.
P.P.S. Parim kala on vorst. Seda nõrkust teades polnud kassi raamimine keeruline.
Filtrite kasutamine
Artiklis näitasin tavalist viisi, kuidas meetodi puhul teisele tegevusele lülituda startActivity() näidatakse praegune klass ja klass üleminekule. Muide, tegevusklass ei pea olema teie rakenduse osa. Kui teate mõne muu rakenduse klassi nime, saate ka sellele lülituda. Kuid saate teisele tegevusele lülituda erineval viisil.
Praktikas vähem levinud, kuid kasulik. Oletame, et teil on juba teine tegevus. Manifestis lisage sellele spetsiaalne filter:
Ja teise tegevuse käivitame sel viisil nupuvajutusega.
Public void onClick(Kuvavaade) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
Asendame pika stringi konstandiga.
Avalik staatiline lõplik String ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(Vaade vaade) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Mida me siis teinud oleme. Teise tegevuse jaoks oleme registreerinud filtri ja määranud nime tegevust atribuudis android:nimi. Mugavuse huvides panin sellesse lihtsalt tegevuse täisnime koos paketi nimega. Klassi konstruktor Kavatsus on mitu ülekoormatud versiooni. Ühes versioonis saate toimingu jaoks määrata stringi. Märkisime oma loodud toimingu, mis on registreeritud teises tegevuses. Süsteem vaatab töö ajal kõigi installitud rakenduste manifeste. Sobivuse otsimisel leiab süsteem meie filtri ja käivitab soovitud tegevuse.
Samal põhimõttel saab alustada ka muude tegevustega. Vaata näidet. Kui kopeerite näite endale ja vaatate selle dokumentatsiooni android.provider.Settings.ACTION_ARPLANE_MODE_SETTINGS, näete, et see kood vastab stringi konstandile public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Võrrelge meie koodiga. Võib eeldada, et võrguühenduseta režiimi seadete tegevusel on filtris see rida.
Filtri kategooria nimi android.intent.category.DEFAULT käsib süsteemil teha vaiketoimingu, milleks on tegevuse alustamine. On teisigi nimesid, mis meid veel ei huvita.
Ja nüüd üks keeruline küsimus. Mis juhtub, kui loote teise tegevuse ja määrate teise tegevusega sama filtri? Ja kontrollime. Loo enda jaoks kolmas tegevus ja kopeeri sellesse plokk koos filtriga teisest tegevusest.
Klõpsame esimeses tegevuses nuppu. Süsteem palub teil valida soovitud valiku.
Kui valite üksuse ALATI siis järgmine kord ei pea valima. Valiku lähtestamiseks avage jaotises Seaded rakenduse atribuudid ja leidke nupp selged vaikesätted.
Tegevuse käivitamine selle nime järgi
Konstruktoris Kavatsus Teine parameeter on klass. Kuid oletame, et on olemas mingi andmebaas, kus tegevuste nimed on märgitud ja vaja on soovitud tegevus selle nime järgi käivitada. Saame stringmuutuja põhjal klassi enda kätte saada ja tegevust alustada.
Proovige ( // tegevusklassi täisnimi String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // hankige klassi klassi objekt>myClass = Class.forName(tegevuseNimi); Intent intent = new Intent(this, myClass); startActivity(intent); ) püüda (ClassNotFoundException e) ( e.printStackTrace(); )
Kuidagi oli mul ülesanne kanda andmed teenusest tegevusse. Algas lahenduse otsimine standardsest SDK-st, kuid kuna aega polnud, tegin andmebaasi kasutamise näol halva otsuse. Aga küsimus oli lahtine ja mõne aja pärast mõtlesin välja õigema viisi, mis SDK-s on – kasutades Message, Handler, Messenger klasse.
Idee
Peame edastama andmed tegevusest teenusesse ja vastupidi. Kuidas me seda teha saame? Oma probleemi lahendamiseks on meil juba olemas kõik, mida vajame. Kõik, mida on vaja, on siduda teenus bindService'i abil tegevusega, edastada vajalikud parameetrid ja veidi maagiat sõnumiklasside kasutamise näol. Ja võlu on kasutada Message eksemplari muutujaid ja eriti replyTo. Meil on seda muutujat vaja selleks, et pääseksime ligi teenuse Messsangeri eksemplarile tegevusest ja teenuses kuni tegevuse Messsangeri eksemplarini. Tegelikult pole see nii lihtne. Vähemalt minu mitte nii andekale meelele. Osaliselt täiustan lihtsalt juba olemasolevat dokumentatsiooni – Teenused Samuti on olemas hea näide StackOverflow's. Igal juhul loodan, et artikkel on vähemalt kellelegi kasulik ja ma ei töötanud asjata.
Näide
Näiteks rakendame teenuse, mis suurendab ja vähendab loenduri väärtust ning tagastab tulemuse tegevuses TextView's. Jätan küljenduskoodi välja, sest seal on kaks nuppu ja tekstiväli – kõik on lihtne.
Rakendamine
Siin on täielik aktiveerimiskood:
Avalik klass MainActivity laiendab tegevust ( avalik staatiline lõplik String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; lõplik sõnumitooja sõnumitooja= new Messenger(new IncomingHandler()); Messenger toServiceMessenger; @Override public void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState) ), (testServConn = new TestServiceConnection()), Context.BIND_AUTO_CREATE); ) @Alista public void onDestroy()( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(View nupp)( Sõnum.msg get(null, TestService.COUNT_PLUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) püüda (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(View nupp)( Sõnumi sõnum = Message.obtain(null, TestService.COUNT_MIUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) püüda (RemoteException e) ( e.printStackTrace(); ) ) privaatklass IncomingHandler laiendab töötlejat ( @Override public void handleMessage(Message msg)( switch (msg.what) ( case TestService.GET_COUNT: Log.d(TAG, "(activity)...get count"); testTxt.setText(""+msg.arg1); murda; ) ) ) privaatklass TestServiceConnection juurutab ServiceConnectioni ( @Override public void onServiceConnected(ComponentName name, IBinder service) ( toServiceMessenger = new Messenger(service); //send Algne väärtus loendur Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = sõnumitooja; msg.arg1 = 0; //meie loenduri proovi ( toServiceMessenger.send(msg); ) püüda (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
Las ma seletan. Tegevuse loomisel seome end kohe teenusega, juurutades ServiceConnection liidese ja saadame teenusele sõnumi “seadista loenduri väärtus”, jättes nulli ja luues toServiceMessangeri, edastades IBinderi liidese konstruktorile. Muide, see eksemplar tuleb teenuses tagastada, vastasel juhul tekib NPE. Selle klassi abil saadame teenusele sõnumeid. Ja siin on see maagia - muutujas replyTo salvestame oma teise Messengeri eksemplari - selle, mis saab serverilt vastuse ja selle kaudu toimub suhtlus tegevusega.
Teenusest sõnumi saamiseks kasutame oma Handlerit ja lihtsalt otsime üles vajalikud muutujad ja teeme nendega toiminguid. Nupuklõpsudel (meetodid countIncrClick, countDecrClick) saadame teenusele päringud, määrates soovitud toimingu muutujas msg.what.
Pakett com.example.servicetest; import android.app.Service; import android.content.*; import android.os.*; import android.os.Protsess; import android.util.Log; avalik klass TestService laiendab teenust ( avalik staatiline lõplik int COUNT_PLUS = 1; avalik staatiline lõplik int COUNT_MIINUS = 2; avalik staatiline lõplik int SET_COUNT = 0; avalik staatiline lõplik int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; Messenger Messenger; Messenger toActivityMessenger; @Override public void onCreate()( super.onCreate(); HandlerThread lõime = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread);megetssaLooper(tread). = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messsanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int lipud, int startId) ( return START_STICKY; ) //message handler tegevuse privaatklass IncomingHandler laiendab Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Message msg)( //super.handleMessage(msg); toActivityMessenger = msg.replyTo; lüliti (msg.what) ( suurjuht SET_COUNT: count = msg.arg1; Log.d(MainActivity.TAG, "(service)...set count"); break; case COUNT_PLUS: count++; Log.d(MainActivity.TAG , "(service)...count plus"); break; case COUNT_MIUS: Log.d(MainActivity.TAG, "(service)...count miinus"); count--; break; ) //loenduri saatmine väärtus tegevuses Message outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = loendus; outMsg.replyTo = sõnumitooja; proovi ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) püüda (RemoteException e) ( e.printStackTrace(); ) ) ) )
Kõik analoogselt tegevuses oleva loogikaga. Ma isegi ei tea, kas ma pean midagi selgitama. Ainus punkt on selles, et saadan päringu kohe käepideme sõnumi tegevusele tagasi, kasutades selleks muutujat magic replyTo ja tõmmates ülalt välja soovitud Messengeri. Ja teine punkt, mida ma juba mainisin, on:
@Alista avalik IBinder onBind(Intent arg0) (tagasi messanger.getBinder(); )
ilma milleta kõik kukub. See liidese eksemplar edastatakse teenusele ServiceConnection
Järeldus
Kokkuvõttes. Selline väljamõeldud näide tegevuse ja teenuse vastastikusest mõjust. Mulle tundub see üsna mittetriviaalne suhtlus, kuigi kellelegi võib see teistsugune tunduda.
Küsimused, täpsustused jne. Mis tahes aspektides võib esineda ebatäpsusi, seega kirjutage julgelt ja parandage.
Loodan, et postitus oli lugejatele kasulik.
Tere.
UART-i kaudu saadud andmed on vaja üle kanda Tegevusele. Seda saab teha, luues tegevuses lõime, milles korraldada aja (!isInterrupted()) silmus ja lugeda andmeid UART-puhvrist. Pärast seda, kutsudes välja tegevuse kasutajaliidese lõime - MainActivity.this.runOnUiThread(new Runnable() ), tehke selle tegevusega vajalikud toimingud. Kui aga kutsuda põhitegevusest teisi Tegevusi, siis organiseeritud lõime läbimist ei võimalda andmed vastloodud Tegevustele Kui ma õigesti aru saan, et voost andmete kandmiseks suvalisele Tegevusele tuleb voog luua mitte Tegevuses, vaid Teenuses.
Küsimus: andmed tulid UART kaudu, lõimes (mis on loodud Servce'is) on vaja andmed üle kanda Activitysse, mis on nüüd aktiivne, kuidas seda teha saab ja kas seda üldse tehakse?
1 vastus
Igas tegevuses looge töötleja. Selle tegevuse meetodis onResume() on bindService() tehtud. Seal on üheks parameetriks liides ServiceConnection. Rakendage see vähemalt sama tegevusega. Rakendage selles meetod onServiceConnected(). Selles tagasihelistamises on teenus ise üks parameetritest. Nii et nimetage seda teenust oma setHandler() meetodiks. Edastage seal käimasolevas tegevuses olev Handler. Kuid sisestage sissetulevad andmed UART-i kaudu selle käitleja teenusesse. Muide, Handler töötab tavapäraselt põhilõimel, nii et runOnUiThreadi ei pea käivitama.