Applikationen består inte alltid av en enda skärm. Vi har till exempel skapat ett mycket användbart program och användaren vill veta vem dess författare är. Han klickar på knappen "Om" och kommer till en ny skärm där det finns användbar information om versionen av programmet, författaren, webbplatsens adress, hur många katter författaren har, etc. Se en aktivitetsskärm som en webbsida med en länk till en annan sida. Om du tittar på koden i filen MainActivity.java från tidigare lektioner kommer du att se att vår klass Huvudaktivitet gäller även Aktivitet(eller hans arvingar) eller, för att vara mer exakt, ärvt från honom.
Public class MainActivity utökar AppCompatActivity
Som du kanske gissar borde vi skapa en ny klass som kan se ut Huvudaktivitet och sedan på något sätt byta till det på knappklick.
För experimentet kommer vi att ta programmet från första lektionen och använda en knapp för experiment (eller skapa ett nytt projekt med en knapp på skärmen). Låt oss sedan skapa ett nytt formulär för att visa användbar information. Låt oss till exempel visa användaren vad katten gör när den går åt vänster och höger. Håller med, detta är mycket viktig information som ger nyckeln till att nysta upp universum.
Vi kommer att skapa en ny aktivitet manuellt, även om studion har färdiga mallar. Men det är inget komplicerat och för en bättre förståelse är det användbart att göra allt för hand.
Låt oss skapa en ny XML-uppmärkningsfil activity_about.xml i mappen res/layout. Högerklicka på mappen layout och välj från snabbmenyn Nytt | Layoutresursfil. En dialogruta visas. Ange filnamnet i det första fältet aktivitet_om. I det andra måste du ange rotelementet. Som standard finns den där Constraint Layout. Radera text och skriv in rullningsvy. Att ange några tecken räcker för att studion ska föreslå färdiga alternativ, du kan omedelbart trycka på Enter utan att vänta på den fullständiga inmatningen av ordet:
Vi får motsvarande blankett, i vilken vi infogar elementet textvy.
Information kommer att hämtas från resurser, nämligen från en strängresurs about_text. Nu är den markerad i rött, vilket signalerar frånvaron av information. kunde tryckas Alt+Enter och skriv in text i dialogrutan. Men för vårt exempel kommer den här metoden inte att fungera, eftersom vår text kommer att vara flerradig med kontrolltecken. Så låt oss göra det annorlunda. Låt oss öppna filen res/values/strings.xml och skriv in följande text manuellt:
Vi använde de enklaste HTML-textformateringstaggarna som , , . För vårt exempel räcker det att feta orden som hänvisar till katten och rörelseriktningen. För att översätta text till en ny rad, använd symbolerna \n. Låt oss lägga till ytterligare en strängresurs för titeln på den nya skärmen:
Förstås med markering. Därefter måste du skapa en klass för fönstret AboutActivity.java. Välj från menyn fil | Nytt | Java klass och fyll i de obligatoriska fälten. Till en början räcker det att endast ange namnet. Ta sedan hand om andra områden.
Låt oss ta förberedelserna.
Nu är klassrummet nästan tomt. Låt oss lägga till koden manuellt. Klassen måste ärva från den abstrakta klassen Aktivitet eller dess släktingar FragmentActivity, AppCompatActivity etc. Lägger till utökar aktiviteten. Aktivitetsklassen ska ha en metod onCreate(). Placera muspekaren i klassen och välj från menyn kod | Åsidosätt metoder(Ctrl+O). I dialogrutan letar vi efter önskad klass, du kan skriva de första tecknen på tangentbordet för en snabb sökning. I den skapade metoden måste du anropa metoden setContentView(), som kommer att ladda den förberedda markeringen på skärmen. Vi kommer att ha ett sådant alternativ.
Paket en.alexanderklimov.helloworld; importera android.app.Activity; importera android.os.Bundle; /** * Skapad av Alexander Klimov den 12/01/2014. */ public class AboutActivity utökar aktivitet ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Nu börjar det viktigaste. Vår uppgift är att flytta till en ny skärm när en knapp klickas på den första skärmen. Låt oss gå tillbaka till klassen Huvudaktivitet. Låt oss skriva knappklickshanteraren:
Public void onClick(View view) (Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Här använde jag hanteringsmetoden för knappklick som beskrivs i lektionen.
För att starta en ny skärm måste du skapa en instans av klassen Avsikt och ange den aktuella klassen i den första parametern, och klassen för övergången i den andra, vi har detta Om Aktivitet. Därefter kallas metoden startActivity(), vilket startar en ny skärm.
Om du nu försöker testa applikationen i emulatorn får du ett felmeddelande. Vad gjorde vi för fel? Vi missade ett viktigt steg. Du måste registrera en ny Aktivitet i manifestet AndroidManifest.xml. Hitta den här filen i ditt projekt och dubbelklicka på den. Fönstret för filredigering öppnas. Lägg till en ny tagg
Det är här strängresursen kommer väl till pass about_title. Kör programmet, klicka på knappen och få fram fönstret Om programmet. Således lärde vi oss hur man skapar ett nytt fönster och anropar det med ett knapptryck. Och ett megabekvämt program har dykt upp till vårt förfogande - nu kommer det alltid finnas en hint till hands vad katten gör när den går till vänster.
Återigen vill jag uppmärksamma er på att den andra skapade aktivitetsklassen måste ärvas från klassen Aktivitet eller liknande ( ListActivity etc.), har en XML-uppmärkningsfil (om så krävs) och skrivs i manifestet.
Efter att ha anropat metoden startActivity() en ny aktivitet kommer att starta (i detta fall Om Aktivitet), kommer den att bli synlig och flyttas till toppen av stapeln som innehåller de löpande komponenterna. När du anropar en metod Avsluta() från den nya aktiviteten (eller när hårdvarubakåtstegstangenten trycks ned) kommer den att stängas och tas bort från stacken. Utvecklaren kan också navigera till föregående (eller någon annan) aktivitet med samma metod startActivity().
Programmerare, som katter, är lata varelser. Kom alltid ihåg att du för aktiviteten behöver skapa uppmärkning och en klass som ärver från Aktivitet, och glöm sedan inte att registrera klassen i manifestet - jaha, vad fan.
I det här fallet väljer du från menyn fil | Nytt | aktivitet | grundläggande aktivitet(eller annat mönster). Därefter visas det välbekanta fönstret för att skapa en ny aktivitet. Fyll i de obligatoriska fälten.
Klicka på knappen Avsluta och aktiviteten kommer att vara klar. För att verifiera detta, öppna manifestfilen och leta efter den nya posten. Jag pratar inte om klassfiler och uppmärkning, de kommer att dyka upp framför dig.
Lägg till en ny knapp på skärmen för huvudaktiviteten själv och skriv koden för att navigera till den skapade aktiviteten.
Först skulle jag råda dig att manuellt skapa alla nödvändiga komponenter för en ny aktivitet för att förstå förhållandet mellan klassen, markeringen och manifestet. Och när du får tag på det kan du använda guiden för att skapa aktiviteter för att påskynda saker.
Vi använde det enklaste exemplet för att anropa en annan aktivitetsskärm. Ibland krävs det inte bara att anropa en ny skärm, utan också att överföra data till den. Till exempel användarnamn. I det här fallet måste du använda ett speciellt område extraData, som klassen har Avsikt.
Område extraDataär en lista över par nyckelvärde, som skickas tillsammans med avsikten. Strängar används som nycklar, och för värden kan du använda alla primitiva datatyper, arrayer av primitiver, klassobjekt bunt och så vidare.
För att skicka data till en annan aktivitet, använd metoden putExtra():
Intent.putExtra("Nyckel", "Värde");
Den mottagande aktiviteten bör anropa någon lämplig metod: getIntExtra(), getStringExtra() etc.:
Int count = getIntent().getIntExtra("namn", 0);
Låt oss göra om det föregående exemplet. Vi har redan tre aktiviteter. Den första aktiviteten kommer att ha två textfält och en knapp. Utseendet kan vara som följer:
Vid den andra aktiviteten SecondActivity ställ in elementet textvy, där vi kommer att visa texten från den första aktiviteten. Låt oss skriva följande kod för metoden onCreate() vid den andra aktiviteten.
@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String present = "munkhål"; TextView infoTextView = (TextView)find RViewById .id.textViewInfo); infoTextView.setText(användare + " , du fick " + gåva); )
Om vi nu kör programmet och helt enkelt anropar det andra fönstret, som beskrivs i den första delen av artikeln, kommer vi att se standardinskriften ZhYvotnoe, du fick ett munkhål. Håller med, det är ganska synd att få sådana meddelanden.
Vi fixar situationen. Lägg till kod till den första aktiviteten:
Public void onClick(View view) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Intent intention.Second class); // tryck in texten från det första textfältet till användarnamnsnyckeln intent.putExtra("användarnamn", userEditText.getText().toString()); // tryck in texten från det andra textfältet till presentnyckeln intent.putExtra("gåva", giftEditText.getText().toString()); startActivity(avsikt); )
Vi placerade i en speciell föremålsbehållare Avsikt två nycklar med värden hämtade från textfält. När användaren anger data i textfälten hamnar de i den här behållaren och skickas till den andra aktiviteten.
Den andra aktiviteten ska vara redo att varmt ta emot meddelanden enligt följande (markerad med fet stil).
// Standardvärden String user = "LIFE"; String present = "munkhål"; user = getIntent().getExtras().getString("användarnamn"); gift = getIntent().getExtras().getString("gift"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(användare + " , du fick " + present);
Nu ser budskapet inte så stötande ut, men till och med trevligt för vissa. I komplexa exempel är det önskvärt att lägga till validering under databehandling. Det finns situationer när du startar en andra aktivitet med tomma data som null, vilket kan krascha programmet.
I vårt fall vet vi att vi väntar på ett strängvärde, så koden kan skrivas om så här:
intent intent = getIntent(); user = intent.getStringExtra("användarnamn");
User = getIntent().getStringExtra("användarnamn");
Programmet har en nackdel - det framgår inte från vem vi får hälsningar. Alla väluppfostrade apor kommer inte att acceptera en gåva från en anonym källa. Så för läxor, lägg till ett annat textfält för att ange namnet på användaren som skickar meddelandet.
Google rekommenderar att du använder följande format för nycklar: ditt paketnamn som prefix, följt av själva nyckeln. I det här fallet kan du vara säker på att nyckeln är unik när du interagerar med andra applikationer. Ungefär så här:
Public final static String USER = "ru.alexanderklimov.myapp.USER";
Det räcker inte alltid att bara skicka data till en annan aktivitet. Ibland behöver man få tillbaka information från en annan aktivitet när den är stängd. Om vi tidigare använde metoden startActivity(Intent intent), så finns det en relaterad metod startActivityForResult(Intent intent, int RequestCode). Skillnaden mellan metoderna ligger i den extra parametern begär kod. Det är i princip bara ett heltal som du kan tänka på själv. Det är nödvändigt för att skilja från vem resultatet kom. Låt oss säga att du har fem extra skärmar och du tilldelar värden från 1 till 5 till dem, och från den här koden kan du bestämma vems resultat du behöver bearbeta. Du kan använda värdet -1, då blir det likvärdigt med att anropa metoden startActivity(), dvs. vi får inget resultat.
Om du använder metoden startActivityForResult(), då måste du åsidosätta metoden i koden för att få resultatet onActivityResult() och bearbeta resultatet. Förvirrad? Låt oss ta en titt på ett exempel.
Låt oss säga att du är en detektiv. Information inkom om att två korvbitar och andra produkter stals från bordet hos en inflytelserik person i restaurangen. Misstanke föll på tre misstänkta - en kråka, en jävla hund och katten Vaska.
En av besökarna gav en serie bilder från sin ponton iPhone:
Det finns också vittnesmål från ett annat vittne: Och Vaska lyssnar och äter.
Vi skapar ett nytt projekt Sherlock med två aktiviteter. På den första skärmen kommer det att finnas en knapp för att växla till den andra skärmen och en textetikett som visar namnet på tjuven.
Den andra skärmen kommer att ha en grupp radioknappar:
Eftersom vi kommer att vänta på ett svar från den andra skärmen måste vi använda metoden startActivityForResult() på den första skärmen där vi skickar variabeln CHOOSE_THIEF som en parameter begär kod.
statisk slutlig privat int CHOOSE_THIEF = 0; public void onClick(View v) (Intent questionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Titta på koden. När du klickar på knappen kommer vi att arbeta med den andra skärmen Välj Aktivitet och starta den andra skärmen i väntan på resultatet.
Vi går vidare till den andra skärmen och vi kommer att skriva koden för den andra aktiviteten.
Offentlig slutlig statisk String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Jävla hund"); break; case R.id .radioCrow: answerIntent.putExtra(THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra(THIEF, "Przewalskis häst"); break; default: break; ) setResult(RESULT_OK, answerIntent); finish (); )
Allt är enkelt här, när detektiven väljer namnet på brottslingen, sedan genom metoden putExtra() vi skickar nyckelns namn och dess värde.
För enkelhetens skull, efter valet, stänger vi omedelbart det andra fönstret och skickar värdet innan vi stänger RESULTAT_OK för att tydliggöra att valet är gjort. Om användaren stänger skärmen via Tillbaka-knappen kommer värdet att skickas RESULT_CANCELED.
Metod setResult() tar två parametrar: den resulterande koden och själva resultatet, representerat som en avsikt. Den resulterande koden säger vilket resultat aktiviteten slutade med, i regel är det antingen Activity.RESULT_OK, eller Activity.RESULT_CANCELED. I vissa fall behöver du använda din egen returkod för att hantera applikationsspecifika alternativ. Metod setResult() stöder alla heltalsvärden.
Om du skickar data explicit genom knappen, skulle det vara trevligt att lägga till en metod Avsluta() att stänga den andra aktiviteten som onödig. Om övergången sker genom knappen Tillbaka, är detta inte nödvändigt.
Om aktiviteten stängdes av användaren när hårdvarans bakåtknapp trycktes, eller om metoden Avsluta() kallades före metoden setResult(), kommer den resulterande koden att ställas in på RESULT_CANCELED och den returnerade avsikten visar värdet null.
Vi återgår till den första skärmen. Den första skärmen väntar på svar från den andra skärmen, så du måste lägga till en metod i koden 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_THE if (resultCode == RESULT_OK) ( String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // radera text ) ) )
Metoden förväntar sig inkommande data med kod CHOOSE_THIEF, och om sådan data kommer, extraherar sedan värdet från nyckeln Välj Activity.THIEF använda metoden getStringExtra. Vi matar ut det resulterande värdet till textvy(variabel infoTextView). Om vi återvände till skärmen via Tillbaka-knappen, raderar vi helt enkelt texten.
När den underordnade aktiviteten är stängd inuti den överordnade komponenten, avfyrar hanteraren onActivityResult(). Hanterare onActivityResult() tar flera parametrar.
Om den underordnade aktiviteten avslutades oväntat, eller om ingen resultatkod angavs innan den stängdes, blir denna parameter lika med Activity.RESULT_CANCELED.
Vi startar projektet, klickar på knappen och går till den andra skärmen. Där väljer vi ett av alternativen. Om du väljer en kråka stängs skärmen och namnet på brottslingen kommer att visas på den första skärmen. Om du väljer en hund kommer hans namn att visas.
Förresten, om du väljer en katt kommer dess namn inte att visas! Kolla och se själv. Du kommer att fråga varför? Elementär Watson! Gärningsmannen tog inte hänsyn till en viktig detalj. Restaurangen var under övervakning av videokameror och inspelningen visade vem som faktiskt stal korven och ramade in katten. Vaska, håll ut!
P.S. Om något först verkade obegripligt, kommer mycket att bli tydligt med övning. Att skicka data mellan skärmar är vanligt i applikationer, och du kommer att studera exemplet mer än en gång.
P.P.S. Den bästa fisken är korv. Att känna till denna svaghet var det inte svårt att rama in katten.
I artikeln visade jag ett vanligt sätt att byta till en annan aktivitet, när i metoden startActivity() den aktuella klassen och klassen till övergången anges. Aktivitetsklassen behöver förresten inte vara en del av din ansökan. Om du känner till namnet på en klass från en annan applikation kan du byta till den också. Men du kan byta till en annan aktivitet på ett annat sätt.
Mindre vanligt i praktiken, men användbart. Låt oss säga att du redan har en andra aktivitet. Lägg till ett speciellt filter i manifestet:
Och vi startar den andra aktiviteten genom ett knapptryck på detta sätt.
Public void onClick(View view) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
Låt oss ersätta en lång sträng med en konstant.
Public static final String ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(View view) (startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Så vad har vi gjort. För den andra aktiviteten har vi registrerat ett filter och angett ett namn för handling i attribut android:namn. För enkelhetens skull lägger jag bara in det fullständiga namnet på aktiviteten med namnet på paketet. Klasskonstruktör Avsikt har flera överbelastade versioner. I en version kan du ange en sträng för åtgärden. Vi angav vår skapade åtgärd, som registreras i den andra aktiviteten. Systemet tittar på manifesten av alla installerade applikationer under drift. När du söker efter en matchning hittar systemet vårt filter och startar önskad aktivitet.
Enligt samma princip kan du starta andra aktiviteter. Titta på ett exempel. Om du kopierar exemplet till dig själv och tittar i dokumentationen för android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, kommer du att se att den här koden motsvarar en strängkonstant public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Jämför med vår kod. Du kan anta att inställningsaktiviteten för offlineläge har denna rad i filtret.
Filterkategorinamn android.intent.category.DEFAULT säger till systemet att vidta standardåtgärden, som är att starta aktiviteten. Det finns andra namn som inte är intressanta för oss ännu.
Och nu en knepig fråga. Vad händer om du skapar en annan aktivitet och anger samma filter som den andra aktiviteten? Och låt oss kolla. Skapa en tredje aktivitet för dig själv och kopiera blocket med filtret från den andra aktiviteten in i det.
Vi klickar på knappen i den första aktiviteten. Systemet kommer att be dig välja önskat alternativ.
Om du väljer objektet ALLTID nästa gång behöver du inte välja. För att återställa valet, gå till applikationsegenskaperna i Inställningar och hitta knappen rensa standardinställningar.
I konstruktör Avsikt Den andra parametern är klassen. Men anta att det finns någon sorts databas där namnen på aktiviteterna anges och vi måste starta den önskade aktiviteten med dess namn. Vi kan få själva klassen baserat på strängvariabeln och starta aktiviteten.
Testa ( // Fullständigt namn på aktivitetsklassen String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // hämta Class Class-objektet>myClass = Class.forName(activityName); Intent intent = new Intent(this, myClass); startActivity(avsikt); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
På något sätt hade jag till uppgift att överföra data från tjänsten till aktiviteten. Sökandet efter en lösning i standard-SDK:n började, men eftersom det inte fanns tid tog jag ett dåligt beslut i form av att använda en databas. Men frågan var öppen och efter ett tag kom jag på ett mer korrekt sätt som finns i SDK - genom att använda klasserna Message, Handler, Messenger.
Vi behöver överföra data från verksamheten till tjänsten och vice versa. Hur kan vi göra det? För att lösa vårt problem har vi redan allt vi behöver. Allt som behövs är att binda tjänsten till aktiviteten med bindService, skicka nödvändiga parametrar och lite magi i form av att använda Message-klasserna. Och magin är att använda Message-instansvariabler och i synnerhet replyTo. Vi behöver den här variabeln så att vi kan hänvisa till Messanger-tjänsteinstansen från aktiviteten och i tjänsten till Messanger-instansen av aktiviteten. Egentligen är det inte så enkelt. Åtminstone för mitt inte så begåvade sinne. Dels förbättrar jag bara den dokumentation som redan finns - Services Det finns också ett bra exempel på StackOverflow. Jag hoppas i alla fall att artikeln kommer att vara användbar för åtminstone någon och jag arbetade inte förgäves.
Som ett exempel kommer vi att implementera en tjänst som kommer att öka och minska värdet på räknaren och returnera resultatet i aktiviteten, i TextView. Jag kommer att utelämna layoutkoden, eftersom det finns två knappar och ett textfält - allt är enkelt.
Här är hela aktiveringskoden:
Public class MainActivity utökar 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 saved) (Bundle saved. onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt); bindService(new Intent(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; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(View button)( Message msg = Message.obtain(null, TestService.COUNT_MINUS); msg .svara till = budbärare; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) privat klass IncomingHandler utökar Handler ( @Override public void handleMessage(Message msg)( switch (msg.what) (fall TestService. GET_COUNT: Log.d(TAG, "(aktivitet)...get count"); testTxt.setText(""+msg.arg1); break; ) ) ) privat klass TestServiceConnection implementerar ServiceConnection ( @Override public void onServiceConnected(ComponentName namn, IBinder-tjänst) ( toServiceMessenger = new Messenger(tjänst); //skicka det initiala räknarvärdet Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = messenger; msg.arg1 = 0; //vår counter try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
Låt mig förklara. När vi skapar en aktivitet binder vi oss omedelbart till tjänsten genom att implementera ServiceConnection-gränssnittet och skickar ett meddelande till tjänsten "ställ in räknarvärdet" i den, skickar noll och skapar en toServiceMessanger, skickar IBinder-gränssnittet till konstruktören. Denna instans måste förresten returneras i tjänsten, annars blir det NPE. Med hjälp av denna klass skickar vi meddelanden till tjänsten. Och här är det magi - i variabeln replyTo sparar vi vår andra instans av Messenger - den som får ett svar från servern och det är genom den som kommunikationen med aktiviteten kommer att utföras.
För att få ett meddelande från tjänsten använder vi vår Handler och letar helt enkelt efter de variabler vi behöver och gör åtgärder på dem. Vid knappklick (metoder countIncrClick, countDecrClick) skickar vi förfrågningar till tjänsten och anger önskad åtgärd i variabeln msg.what.
Paket com.example.servicetest; importera android.app.Service; importera android.content.*; importera android.os.*; importera android.os.Process; importera android.util.Log; public class TestService utökar Service ( 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) (retur messanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int-flaggor, int startId) (retur START_STICKY; ) //meddelandehanterare aktivitet privat klass IncomingHandler utökar Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Message msg)( //super.handleMessage(msg); toActivityMess enger = msg.replyTo; switch (msg.what) (fall 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_MINUS: Log.d(MainActivity.TAG, "(service)...count minus"); count--; break; ) //sända räknaren värde i aktivitetsmeddelande outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = räkna; outMsg.replyTo = budbärare; try ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) ) )
Allt i analogi med logiken i aktiviteten. Jag vet inte ens om jag behöver förklara något. Den enda poängen är att jag omedelbart skickar förfrågan tillbaka till aktiviteten i handleMessage, använder den magiska replyTo-variabeln för detta och drar ut önskad Messenger ovan. Och den andra punkten som jag redan har nämnt är:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
utan vilken allt kommer att falla. Det är denna gränssnittsinstans som kommer att skickas till ServiceConnection
Allt som allt. Ett sådant konstruerat exempel på samspelet mellan en verksamhet och en tjänst. Det verkar för mig som en ganska icke-trivial interaktion, även om det kan tyckas annorlunda för någon.
Frågor, förtydliganden m.m. Det kan finnas felaktigheter om några aspekter, så skriv och rätta gärna.
Jag hoppas att inlägget var till hjälp för läsarna.
Senast uppdaterad: 2018-03-04
Ett Intent-objekt används för att överföra data mellan två aktiviteter. Genom metoden putExtra() kan du lägga till en nyckel och dess tillhörande värde.
Till exempel, överföra strängen "Hello World" från den aktuella aktiviteten till SecondActivity med nyckeln "hej":
// skapa en avsikt för att starta SecondActivity Intent avsikt = new Intent(detta, SecondActivity.class); // skickar ett objekt med nyckeln "hej" och värdet "Hello World" avsikt. putExtra("hej", "Hello World"); // starta SecondActivity startActivity(avsikt);
För att överföra data används putExtra()-metoden, som gör att du kan överföra data av de enklaste typerna - String, int, float, double, long, short, byte, char, arrays av dessa typer, eller ett objekt av Serializable gränssnitt som ett värde.
För att få den inlämnade informationen när SecondActivity laddas kan du använda metoden get() som skickar nyckeln till objektet:
Bundle-argument = getIntent().getExtras(); String name = arguments.get("hej").toString(); // Hej världen
Beroende på vilken typ av data som skickas kan vi använda ett antal metoder på Bundle-objektet när vi tar emot det. Alla tar en objektnyckel som en parameter. De viktigaste är:
get() : generisk metod som returnerar ett värde av typen Objekt. Följaktligen måste det mottagande fältet, detta värde konverteras till önskad typ
getString() : returnerar ett objekt av typen String
getInt() : returnerar ett int-värde
getByte() : returnerar ett bytevärde
getChar() : returnerar ett värde av typen char
getShort() : returnerar ett värde av typen kort
getLong() : returnerar ett långt värde
getFloat() : returnerar ett flytvärde
getDouble() : returnerar ett dubbelt värde
getBoolean() : returnerar ett booleskt värde
getCharArray(): returnerar en array av char-objekt
getIntArray(): returnerar en array av int-objekt
getFloatArray(): returnerar en array av flytande objekt
getSerializable() : returnerar ett objekt i gränssnittet Serializable
Låt oss definiera två aktiviteter i vårt projekt: MainActivity och SecondActivity.
Låt oss definiera mottagandet av data i SecondActivity-koden:
Paketet com.example.eugene.serializeapp; importera android.support.v7.app.AppCompatActivity; importera android.os.Bundle; importera android.widget.TextView; public class SecondActivity utökar AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 616, ); Bundle arguments = getIntent().getExtras(); if(arguments!=null)( String name = arguments.get("name").toString(); String company = arguments.getString("företag"); int pris = arguments.getInt("pris"); textView.setText("Namn: " + namn + "\nFöretag: " + företag + "\nPris: " + pris); ) setContentView(textView); ) )
I det här fallet, i SecondActivity, hämtar vi all data från Bundle-objektet och visar den i TextView-textfältet. Det antas att tre element kommer att skickas till denna aktivitet - två strängar med nycklarnas namn och företag och ett nummer med prisnyckeln.
Låt oss nu definiera dataöverföringen till SecondActivity. Låt oss till exempel definiera följande gränssnitt för MainActivity i filen activity_main.xml:
Tre textfält för datainmatning och en knapp definieras här.
I klassen MainActivity definierar du följande innehåll:
Paketet com.example.eugene.serializeapp; importera android.content.Intent; importera android.support.v7.app.AppCompatActivity; importera android.os.Bundle; importera android.view.View; importera android.widget.EditText; public class MainActivity utökar AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = find. .name); final EditText companyText = findViewById(R.id.company); final EditText priceText = findViewById(R.id.price); String name = nameText.getText().toString(); String company = companyText.getText( ).toString(); int pris = Integer.parseInt(priceText.getText().toString()); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra("namn", namn); avsikt. putExtra("företag", företag); avsikt. putExtra("pris", pris); startActivity(avsikt); ) )
I knappklickshanteraren får vi in data i EditText-textfälten och skickar dem till Intent-objektet med putExtra()-metoden. Sedan startar vi SecondActivity.
Som ett resultat, när du klickar på knappen, kommer SecondActivity att startas, som kommer att ta emot en del data som anges i textfälten.
I exemplet ovan skickades enkel data - siffror, strängar. Men vi kan också överföra mer komplexa data. I det här fallet används serialiseringsmekanismen.
Låt oss till exempel ha en produktklass definierad i vårt projekt:
Paketet com.example.eugene.serializeapp; importera java.io.Serialiserbar; public class Product implementerar Serializable (privat strängnamn; privat strängföretag; privat int-pris; offentlig produkt(strängnamn, strängföretag, int-pris)( this.name = name; this.company = company; this.price = pris; ) 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() ( returpris; ) public void setPrice(int price) ( this.price = price; ) )
Observera att den här klassen implementerar gränssnittet Serializable. Låt oss nu ändra MainActivity-koden:
Paketet com.example.eugene.serializeapp; importera android.content.Intent; importera android.support.v7.app.AppCompatActivity; importera android.os.Bundle; importera android.view.View; importera android.widget.EditText; public class MainActivity utökar AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( final EditText nameText = find. .name); final EditText companyText = findViewById(R.id.company); final EditText priceText = findViewById(R.id.price); String name = nameText.getText().toString(); String company = companyText.getText( ).toString();int price = Integer.parseInt(priceText.getText().toString()); Produktprodukt = ny produkt(namn, företag, pris); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra(Product.class.getSimpleName(), produkt); startActivity(avsikt); ) )
Nu skickas ett produktobjekt istället för tre olika data. Nyckeln är resultatet av metoden Product.class.getSimpleName(), som i huvudsak returnerar klassens namn.
Och ändra klassen SecondActivity:
Paketet com.example.eugene.serializeapp; importera android.support.v7.app.AppCompatActivity; importera android.os.Bundle; importera android.widget.TextView; public class SecondActivity utökar AppCompatActivity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 616, ); Bundle arguments = getIntent().getExtras(); slutproduktprodukt; if(arguments!=null)( product = (Produkt) arguments.getSerializable(Product.class.getSimpleName()); textView.setText("Namn: " + product.getName() + "\nFöretag: " + product.getCompany() + "\nPris: " + String.valueOf(product.getPrice())); ) setContentView(textView); ) )
Metoden getSerializable() används för att hämta data eftersom klassen Product implementerar gränssnittet Serializable. Således kan vi skicka ett enda objekt istället för en uppsättning olika data.