Gjennom årene har jeg sett forskjellige implementeringer av Android-navigasjonsmønsteret. Noen applikasjoner brukte bare aktiviteter, mens andre aktiviteter ble blandet med utdrag og / eller egendefinerte visninger ( Egendefinerte visninger ).
En av mine favorittfragmentimplementeringsimplementeringer er basert på filosofien 'One-Activity-Multiple-Fragments' (' En-aktivitet-flere fragmenter ”), Eller bare fragmenteringsnavigasjonsmønsteret ( Fragment navigasjonsmønster ), der hver skjerm i applikasjonen er en fullskjermsfragment og alle eller de fleste av disse fragmentene er innenfor en aktivitet.
Denne tilnærmingen forenkler ikke bare hvordan navigasjonen implementeres, men har også bedre ytelse og gir deg derfor en bedre brukeropplevelse.
I denne artikkelen vil vi utforske noen vanlige implementeringer av navigasjonsmønstre på Android, og deretter introdusere det kodebaserte navigasjonsmønsteret. En prøveapplikasjon som implementerer dette mønsteret, finner du i GitHub .
En typisk Android-applikasjon som bare bruker aktiviteter er organisert i en tretypestruktur (nøyaktig i en rettet graf) der hovedaktiviteten er initiert av bærerakett . Mens du surfer på applikasjonen, er det en “ bakstabel ”Av aktiviteten som opprettholdes takket være operativsystemet.
Et enkelt eksempel er vist i følgende diagram:
Aktivitet A1 er inngangspunktet for applikasjonen vår (for eksempel representerer den en startskjerm eller en hovedmeny), og fra det tidspunktet kan brukeren navigere til A2 eller A3. Når du trenger å kommunisere mellom aktivitetene du kan bruke startActivityForResult () Eller du kan dele et globalt tilgjengelig forretningslogisk objekt mellom begge aktivitetene.
Når du trenger å legge til en ny aktivitet, må du følge følgende trinn:
Selv om dette navigasjonsdiagrammet er en ganske forenklet tilnærming; men det kan bli veldig komplisert når du trenger det manipulere av bakstabel eller når du må bruke den samme aktiviteten på nytt flere ganger, for eksempel når du vil at brukeren skal navigere gjennom forskjellige opplæringsskjermbilder, men hver skjerm bruker den samme aktiviteten som en base.
Heldigvis har vi verktøy for disse sakene kalt gjøremål og noen guider for en navigering av bakstabel passende .
Så, med API-nivå 11, kom fragmentene ...
Android introduserer utdrag i Android 3.0 (API-nivå 11), primært for å støtte mer dynamiske og fleksible UI-oppsett på store skjermer som nettbrett. Siden skjermen på et nettbrett er mye større enn en telefon, er det mer plass til å blande og matche UI-komponenter. Utdrag støtter disse oppsettene uten at du trenger å håndtere komplekse endringer i visningshierarkiet. Ved å dele opp en aktivitets layout i biter, kan du endre utseendet til aktiviteten i løpetid og beholde endringene i en aktivitetsstabel som administreres av aktiviteten. - sitat fra Google Guide API for fragmenter .
Dette nye leketøyet tillot utviklere å lage et flerpanel brukergrensesnitt og være i stand til å gjenbruke komponentene i andre aktiviteter. Noen utviklere elsker dette mens andre Ikke så mye . Hvorvidt det skal brukes Snippets eller ikke, er en populær debatt, men jeg tror alle er enige i at snippets gir ekstra kompleksitet, og utviklere må forstå dem ordentlig for å kunne bruke dem.
Jeg begynte å se flere og flere eksempler der fragmentene ikke bare representerte en del av skjermen, men hele skjermen var et fragment innenfor en aktivitet. Det var en gang jeg så et oppsett der hver aktivitet hadde nøyaktig ett fullskjermsutdrag og ingenting annet, og den eneste grunnen til at aktivitetene fantes var å lagre utdragene. Bortsett fra designfeilen, er det et annet problem med denne tilnærmingen. Ta en titt på diagrammet nedenfor:
Hvordan kan A1 kommunisere med F1? Det som skjer er at A1 har full kontroll over F1, fordi den opprettet F1. A1 kan passere en pakke, for eksempel i opprettelsen av F1, eller den kan påkalle sine offentlige metoder. Hvordan kan F1 kommunisere med A1? Vel, det er mer komplisert, det kan løses med et mønster av tilbakeringing / observatør der A1 abonnerer på F1 og F1 varsler A1.
Men hvordan kan A1 og A2 kommunisere? Som forklart ovenfor, kunne de kommunisere via startActivityForResult () .
Og nå det virkelige spørsmålet: Hvordan kan F1 og F2 kommunisere? Selv i dette tilfellet kan vi ha en forretningslogisk komponent som er tilgjengelig globalt, og som kan brukes til å formidle data. Men den komponenten tilsvarer ikke alltid fancy design. Hva om F2 trenger å overføre informasjon til F1 mer direkte? I et slikt tilfelle, med et mønster Ring tilbake F2 kan varsle A2, så ender A2 med et resultat, og resultatet kan lagres av A1 som kan varsle F1.
Denne tilnærmingen krever mye kode kokeplate og blir raskt en kilde til bugs , smerte og sinne.
Hva om vi kunne kvitte oss med alle aktivitetene og bare beholde en av dem som vil beholde resten av fragmentene?
Over tid begynte jeg å bruke 'One-Activity-Multiple-Fragments' -mønsteret i de fleste av programmene mine, og jeg bruker det fortsatt. Det er mange diskusjoner der ute om denne tilnærmingen eller filosofien, for eksempel her Y her . Det jeg savnet var et spesifikt eksempel som jeg kan se og teste for meg selv.
La oss se på følgende diagram et øyeblikk:
Nå har vi bare en containeraktivitet, og vi har flere fragmenter som igjen er i en trestypestruktur. Navigering mellom dem håndteres av FragmentManager , dette har sitt bakstabel .
Du vil innse at nå har vi ikke startActivityForResult () men vi kan implementere mønsteret tilbakeringing / observatør . La oss nå se på noen fordeler og ulemper ved denne tilnærmingen:
Nå som vi bare har en aktivitet, trenger vi ikke lenger å oppdatere manifestet hver gang vi legger til en ny skjerm. I motsetning til aktiviteter, trenger vi ikke å erklære fragmentene.
Dette kan virke som en liten ting, men for større applikasjoner med mer enn 50 aktiviteter kan dette forbedre lesbarheten til AndroidManifest.xml fil.
Se på manifestfilen for eksempelprogrammet, som har flere skjermer. Manifestfilen holdes superenkel.
package='com.exarlabs.android.fragmentnavigationdemo.ui' >
I eksempelkoden min vil du legge merke til at jeg bruker NavigationManager som i mitt tilfelle blir injisert til hvert av fragmentene. Denne lederen kan brukes som et sentralt sted for hogst , ledelse bakstabel blant annet slik at surfeatferd er frikoblet fra resten av forretningslogikken og ikke spres over implementeringer av forskjellige skjermer.
La oss forestille oss en situasjon der vi ønsker å starte en skjerm, der brukeren kan velge noen elementer fra en liste over personer. Du vil også sende noen filtreringsargumenter, for eksempel alder, yrke og kjønn.
Når det gjelder aktiviteter, vil du skrive:
Intent intent = new Intent(); intent.putExtra('age', 40); intent.putExtra('occupation', 'developer'); intent.putExtra('gender', 'female'); startActivityForResult(intent, 100);
Da må du definere onActivityResult et sted nede og håndtere resultatet.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); }
Mitt personlige problem med denne tilnærmingen er at disse argumentene er 'statister' og ikke er påkrevde, så jeg må sørge for at mottaksaktiviteten håndterer de forskjellige sakene, når en ekstra mangler. Senere når en refactoring er ferdig og når ekstra, for eksempel 'alder' ikke lenger er nødvendig, må jeg se gjennom hele koden der denne aktiviteten startet og sørge for at alle tilleggene er riktige.
Også, ville det ikke vært bedre om resultatet (folkelisten) vil komme som _List_ og ikke i seriell form som deretter må deserialiseres?
Når det gjelder snippebasert surfing, er alt mer greit. Alt du trenger å gjøre er å skrive en metode i NavigationManager kalt startPersonSelectorFragment () med de nødvendige argumentene og med en implementering Ring tilbake .
mNavigationManager.startPersonSelectorFragment(40, 'developer', 'female', new PersonSelectorFragment.OnPersonSelectedListener() { @Override public boolean onPersonsSelected(List selection) { [do something] return false; } });
Eller med RetroLambda
mNavigationManager.startPersonSelectorFragment(40, 'developer', 'female', selection -> [do something]);
Mellom aktiviteter kan vi bare dele en pakke som inneholder primitive eller serielle data. Nå med fragmenter kan vi implementere et mønster Ring tilbake der for eksempel F1 kan lytte til F2 som passerer vilkårlige objekter. Ta en titt på de forrige implementeringseksemplene til Ring tilbake , som returnerer en _Liste_.
Dette blir tydelig når du bruker en skuff som for eksempel har 5 menyelementer, og på hver side skal skuffen vises igjen.
I tilfelle ren aktivitet surfer, bør hver side blåses opp og starte skuffen, men selvfølgelig er dette dyrt.
I diagrammet som vises kan du se flere fragmenter av rot eller rotfragmenter (FR *) som er skjermutklipp som er tilgjengelige direkte fra skuffen, og skuffen er bare tilgjengelig når disse utdragene vises. Alt til høyre for den markerte linjen i diagrammet er der som et eksempel på et vilkårlig navigasjonsskjema.
Siden den inneholder aktiviteten inneholder skuffen, har vi bare en forekomst av skuffen, så hvert navigasjonstrinn der skuffen skal være synlig du trenger ikke å starte den på nytt . Fortsatt ikke overbevist om hvordan alt fungerer? Ta en titt på prøveappen min der bruken av skuffer vises.
Min store frykt har alltid vært at hvis jeg bruker fragmentnavigeringsmønsteret i et prosjekt, så vil jeg på et tidspunkt møte et ukjent problem som vil være vanskelig å løse rundt kompleksiteten til fragmentene, tredjepartsbiblioteker og forskjellige versjoner av System Operasjonelt. Hva om jeg måtte bryte alt jeg har gjort så langt?
Faktisk må du løse problemene med nestede fragmenter , tredjepartsbiblioteker som bruker utdrag som ShinobiControls , ViewPagers Y FragmentStatePagerAdapters .
Jeg innrømmer at det å få nok erfaring med fragmenter for å løse disse problemene var en lang prosess. Men i hvert tilfelle var problemet ikke at filosofien er dårlig, men at han ikke forsto fragmenter nok. Men hvis du forstår fragmenter bedre enn jeg gjorde på den tiden, vil du ikke ha noe problem.
De eneste ulempene jeg kan nevne nå er at vi kan finne problemer som ikke er trivielle å løse, fordi det ikke er noe modent bibliotek som viser alle de komplekse scenariene til en kompleks applikasjon med fragmentbasert navigering.
I denne artikkelen har vi sett et alternativ til å implementere navigering i en applikasjon Android . Mønsteret ble sammenlignet med den tradisjonelle navigasjonsfilosofien som bruker aktiviteter, og vi så noen veldig gode grunner til at det er fordelaktig å bruke fragmenter i stedet for den tradisjonelle tilnærmingen.
Hvis du ikke har vurdert det ennå, sjekk ut demo-appen i distribusjonen GitHub . Ikke vær redd for å bidra med gode eksempler som bedre kan demonstrere bruken.
I slekt: Topp 10 vanligste feil som Android-utviklere gjør