de Gaurav

Stăpânirea contextului Android

Contextul în Android este unul dintre cele mai utilizate și abuzate obiecte. Dar majoritatea articolelor de pe web se concentrează pe definirea a ceea ce este. Nu am putut găsi o resursă bună care să-mi ofere o perspectivă și să mă ajute să înțeleg imaginea de ansamblu. Așa că am încercat să simplific lucrurile cu acest articol.

Stapanirea contextului Android
Ce context să folosești? Credit de imagine: Pexels

Prefaţă

Misiunea mea pentru acest articol este de a vă ajuta să stăpâniți contextul Android. Acesta este unul dintre subiectele de bază ale dezvoltării Android și aproape niciun dezvoltator nu folosește contextul complet și în modul în care a fost conceput.

Am publicat inițial acest articol ca o serie de patru postări pe pagina mea site-ul web. Dacă sunteți interesat să citiți capitol cu ​​capitol, nu ezitați să citiți acolo.

Noțiuni de bază

Ați întâlnit vreodată această întrebare: Care este diferența dintre getContext(), this, getBaseContext(), și getApplicationContext()? Dacă da, acest articol vă va ajuta să vă clarificați cea mai mare parte a confuziei.

Notă: ar trebui să cunoașteți noțiunile de bază ale dezvoltării Android, cum ar fi Activity, Fragments, Broadcast Receiver și alte elemente de bază. Dacă sunteți un dezvoltator nou care tocmai vă începe călătoria în lumea Android, este posibil să nu fie cel mai bun loc pentru a începe.

Ce naiba este contextul?

Să recunoaștem, contextul este una dintre cele mai slab concepute caracteristici ale API-ului Android. L-ai putea numi obiectul „Dumnezeu”.

O aplicație Android sau un set de pachete de aplicații (APK) este un pachet de componente. Aceste componente sunt definite în Manifest și constau în principal din Activitate (UI), Serviciu (Fundal), BroadcastReceiver (Acțiune), ContentProvider (Date) și Resurse (imagini, șiruri etc.).

Dezvoltatorul poate alege să expună aceste componente unui sistem folosind un filtru de intenție. De exemplu: trimiteți e-mail sau partajați imaginea. De asemenea, pot alege să expună componentele numai altor componente ale aplicației lor.

În mod similar, sistemul de operare Android a fost, de asemenea, conceput pentru a expune componente. Câteva bine cunoscute sunt WifiManager, Vibrator și PackageManager.

Contextul este puntea dintre componente. Îl utilizați pentru a comunica între componente, instanțierea componentelor și accesarea componentelor.

Componentele proprii

Folosim contextul pentru a crea instanțe ale componentelor noastre cu Activity, Content Provider, BroadcastReceiver și așa mai departe. Îl folosim și pentru a accesa resurse și sisteme de fișiere.

Componenta dvs. și o componentă de sistem

Contextul acționează ca un punct de intrare în sistemul Android. Unele componente de sistem bine utilizate sunt WifiManager, Vibrator și PackageManager. Puteți accesa WifiManager folosind context.getSystemService(Context.WIFI_SERVICE).

În același mod, puteți utiliza contextul pentru a accesa sistemul de fișiere dedicat aplicației dvs. ca utilizator în sistemul de operare.

Componenta dvs. și o componentă a altei aplicații

Comunicarea între propriile componente și alte componente ale aplicației este aproape identică dacă utilizați abordarea de filtrare a intenției. La urma urmei, fiecare componentă este un cetățean egal în Android.

Un exemplu de intenție utilizată pentru a trimite e-mail este mai jos. Toate componentele care oferă această acțiune intenționată vor fi comunicate utilizatorului care poate alege ce să utilizeze.
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

rezumat

Să fim de acord că totul în Android este o componentă. Contextul este puntea dintre componente. Îl utilizați pentru a comunica între componente, instanțierea componentelor și accesarea componentelor. Sper că definiția este acum clară.

Diferite tipuri de context

Există mai multe moduri în care puteți obține un context (proiectare proastă reperată).

De cele mai multe ori folosim una dintre următoarele situații atunci când avem nevoie de context:

- Application instance as context- Activity	- Instance of your activity (this)	- getApplicationContext() in Activity	- getBaseContext() in Activity- Fragment	- getContext() in Fragment- View	- getContext() in View- Broadcast Receiver	- Context received in broadcast receiver- Service	- Instance of your service (this)	- getApplicationContext() in Service- Context	- getApplicationContext() in Context instance

Împart tipurile de context în două categorii: Context UI și Context non-IU. Această distincție vă va ajuta să înțelegeți n-ways putin mai bine.

Context UI

În realitate, doar ContextThemeWrapper este UI Context – ceea ce înseamnă Context + Tema ta.

Activitatea se extinde ContextThemeWrapper. Acesta este motivul pentru care, atunci când umflați orice XML, vizualizările dvs. sunt tematice. Dacă vă umflați aspectul cu context non-UI, aspectul dvs. nu va fi tematic. Continuați, încercați.

Când utilizați Activity ca substituent pentru context, aveți garantat că utilizați contextul UI. Dacă utilizați metoda getContext din Fragment, utilizați indirect Activity (dacă ați atașat Fragment prin fragmentManager în activitate).

Dar view.getContext() nu este garantat a fi context UI.

Dacă View a fost instanțiat folosind Layout Inflater și a trecut contextul UI, veți obține contextul UI înapoi. Dar dacă a fost instanțiat prin faptul că nu a trecut contextul UI, veți obține celălalt context înapoi.

UI Context- Activity	- Instance of your activity (this)- Fragment	- getContext() in Fragment- View	- getContext() in View (if View was constructed using UI-Context)

Context non-IU

Orice, cu excepția contextului UI, este context non-UI. Din punct de vedere tehnic, orice lucru care nu este ContextThemeWrapper este Context non-UI.

Contextul non-IU este permis aproape tot ce poate face UI-Context (proiectare proastă reperată). Dar, după cum am arătat mai sus, vă pierdeți tematica.

Non-UI Context- Application instance as context- Activity	- getApplicationContext() in Activity- Broadcast Receiver	- Context received in broadcast receiver- Service	- Instance of your service (this)	- getApplicationContext() in Service- Context	- getApplicationContext() in Context instance

Bacsis: Se presupune că toate tipurile de contexte sunt de scurtă durată, cu excepția contextului aplicației. Acesta este cel pe care îl obțineți din clasa aplicației dvs. sau din utilizarea getApplicationContext() atunci când aveți acces la context.

rezumat

Am simplificat-o puțin punând Context în două găleți. Contextul UI este Context + Theming și, din punct de vedere tehnic, orice clasă din care se află o subclasă ContextThemeWrapper vine în această găleată. Contextul non-IU este toate celelalte tipuri de context.

Unde să folosesc ce

Se pune întrebarea: ce va merge prost dacă folosiți contextul într-un loc greșit? Următoarele sunt câteva scenarii:

Scenariul 1

Să spunem că umflați un aspect și că utilizați context non-UI. Ce poate merge prost? Puteți ghici în acest caz: nu veți obține un aspect tematic. Nu-i așa de rău, hmm? Este suportabil.

Scenariul 2

Treceți UI-Context într-un loc unde nu are nevoie decât de acces la resurse sau acces la sistemul de fișiere. Ce nu poate greși? Răspuns scurt: Nimic. Amintiți-vă, UI-Context = Context + Tema. Vă va servi cu plăcere drept context.

Scenariul 3

Treceți UI-Context într-un loc unde nu are nevoie decât de acces la resurse sau acces la sistemul de fișiere dar este o operație lungă în fundal. Spuneți descărcarea unui fișier. Acum ce poate merge prost? Răspuns scurt: Scurgere de memorie.

Dacă aveți noroc și descărcarea se finalizează rapid, obiectul este eliberat și totul este în regulă. Soarele strălucește și păsările ciripesc. Aceasta este una dintre cele mai frecvente greșeli pe care le fac dezvoltatorii. Acestea trimit referința UI-Context la obiectele vii de lungă durată și, uneori, nu are niciun efect secundar.

Cu toate acestea, uneori Android vrea să revendice memorie pentru una dintre cerințele componentei următoare sau cerințele altei componente, și woooshhhh !!! Ai epuizat memoria în aplicația ta. Nu vă faceți griji, vă voi explica.

Scurgere de memorie sau Crash! Asta e.

Da, acesta este cel mai rău scenariu atunci când folosiți contextul într-un loc greșit. Dacă sunteți nou în lumea dezvoltării aplicațiilor, permiteți-mi să vă împărtășesc ceva înțelepciune. Scurgerile de memorie sunt invers proporționale cu experiența dvs. Fiecare dezvoltator Android a scurs memorie. Nu există rușine în a face acest lucru.

Rușinea este când repetați din nou greșeala și o scurgeți în același mod. Dacă scapi de memorie într-un mod diferit de fiecare dată, felicitări crești. Am explicat ce este o scurgere de memorie cu o poveste scurtă aici.

Bine, îl înțeleg, dar care este relația contextului aici?

Spuneți-l cu voce tare, „Proiectare proastă”.

Aproape totul în Android are nevoie de acces la context. Dezvoltatorii naivi trec prin UI Context, pentru că la asta au acces foarte ușor. Trec contextul de viață scurtă (de obicei contextul activității) către obiecte de viață lungă și înainte ca memoria / banii să fie readuse înapoi în sistem, au lovit o criză. Woooshhh !!!

Cel mai simplu mod de a rezolva acest lucru este cu Async Task sau Broadcast Receiver. Dar discutarea lor nu face parte din acest articol.

rezumat

  • Trebuie să accesați lucruri legate de interfața de utilizare? Utilizați UI-Context. Vederile umflate și dialogul sunt cele două cazuri de utilizare la care mă pot gândi.
  • În caz contrar, utilizați context non-IU.
  • Asigurați-vă că nu transmiteți contextul de viață scurtă obiectelor de viață lungă.
  • Transmiteți cunoștințe, ajutați oamenii, plantați copaci și invitați-mă la o cafea.

Sfaturi și trucuri

Care e diferenta dintre this, getApplicationContext() și getBaseContext()?

Aceasta este o întrebare pe care fiecare dezvoltator Android a întâlnit-o în viața lor. Voi încerca să o simplific cât mai mult posibil. Să facem un pas înapoi și să revedem elementele de bază.

Știm că există numeroși factori în dispozitivele mobile. De exemplu, configurația se schimbă tot timpul, iar setările locale se pot schimba explicit sau implicit.

Toate aceste modificări declanșează aplicațiile să se recreeze, astfel încât să poată alege resursele potrivite care se potrivesc cel mai bine cu configurația lor actuală. Portret, Peisaj, Tabletă, chineză, germană și așa mai departe. Aplicația dvs. are nevoie de cele mai bune resurse posibile pentru a oferi cea mai bună experiență de utilizator. Contextul este responsabil pentru furnizarea acelor resurse de potrivire optimă.

Încercați să răspundeți la această întrebare:
Configurarea utilizatorului este în prezent în portret și doriți să accesați resursele peisaj. Sau localizarea utilizatorului este en și doriți să accesați uk resurse. Cum o vei face?

Mai jos sunt câteva metode magice din context:

Stapanirea contextului Android

Există multe metode createX, dar ne interesează în principal createConfigurationContext. Iată cum îl puteți folosi:

Configuration configuration = getResources().getConfiguration();configuration.setLocale(your_custom_locale);context = createConfigurationContext(configuration);

Puteți obține orice tip de context dorit. Când apelați orice metodă din noul context pe care tocmai l-ați obținut, veți avea acces la resurse pe baza configurației pe care ați setat-o.

Știu că este uimitor. Îmi puteți trimite cardul de mulțumire.

În mod similar, puteți crea un context tematic și îl puteți utiliza pentru a umfla vizualizările cu tema dorită.

ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.YOUR_THEME);

Să revenim la întrebarea complicată pe care am pus-o mai sus și să discutăm contextul activității.

Care e diferenta dintre this, getApplicationContext() și getBaseContext()?

Acestea sunt modalitățile posibile prin care puteți obține controlul asupra contextului atunci când vă aflați în Activity scop.

this indică Activitatea în sine, contextul UI și contextul de viață scurtă. getApplicationContext() indică instanța aplicației dvs. care este non-IU și context de viață lungă.

baseContext este baza contextului dvs. de activitate pe care îl puteți seta folosind un model delegat. Știți deja că puteți crea context cu oricare xyz configurația dorită. Puteți combina xyz cunoștințele de configurare cu contextul de bază și activitatea dvs. vor încărca resursele după cum doriți.

Iată metoda pe care o puteți utiliza:

@Overideprotected void attachBaseContext (Context base) {super.attachBaseContext(useYourCustomContext);}

O singura data BaseContext este atașat, activitatea dvs. va delega apeluri către acest obiect. Dacă nu vă atașați la Activitate, rămâne baseContext și primiți Activitate când sunați getBaseContext.

Concluzie

Putem spune că contextul este viața aplicației dvs. Android. Din punctul de vedere al Android, este aplicația dvs. Nu puteți face aproape nimic fără Context. Fără ea, aplicația dvs. este un cod Java simplu.

Context + cod Java => Android

Bine sau rău, este designul pe care îl avem și trebuie să profităm la maximum de el. Din prima parte a acestui articol, am aflat că îl folosim pentru a comunica între componente, instanța componente și componente de acces.

În partea următoare, am aflat că contextul poate fi UI sau NonUI, de scurtă durată sau de lungă durată.

După aceea, am aflat că trebuie să alegeți contextul cu atenție, altfel trebuie să vă ocupați de scurgerile de memorie și alte probleme de interfață.

În cele din urmă, ați văzut că Context este responsabil pentru încărcarea celor mai bune resurse de potrivire pentru aplicația dvs. și o puteți configura după cum doriți. De asemenea, am învățat diferența dintre this, applicationContext și baseContext.

Mulți dezvoltatori vă vor sfătui să utilizați numai contextul aplicației. Nu utilizați Contextul aplicației peste tot, de teama unei scurgeri de memorie. Înțelegeți cauza principală și folosiți întotdeauna contextul potrivit la locul potrivit.

Tu, dragul meu prieten, ești acum un maestru al contextului Android. Puteți sugera următorul subiect pe care doriți să îl înțelegeți. Faceți clic aici pentru a sugera.

Mai jos sunt linkuri din seria originală Stăpânirea contextului Android pe blogul meu.

Capitolul 1

Ce naiba este contextul? De ce avem nevoie de el și care sunt diferitele cazuri de utilizare în dezvoltarea de zi cu zi?

capitolul 2

Simplificarea contextului. Vom discuta câte tipuri de context există și pe care presupuneți să le folosiți.

capitolul 3

Unde se utilizează contextul interfeței de utilizare și unde se utilizează contextul non-interfață. Cum utilizarea contextului într-un loc greșit poate duce la scurgeri de memorie.

capitolul 4

Contextul meu UI îmi oferă, de asemenea, mai multe tipuri de context. Să răspundem la această întrebare și să vedem cum să evităm capcanele obișnuite.

Instruire

Știți că de multe ori aplicația dvs. se blochează deoarece dezvoltatorii dvs. nu folosesc Context în mod corespunzător? Să învățăm împreună. Ofer instruire în Android, Java și Git.

Vrei să stăpânești Teme Android? Urmăriți seria noastră cu mai mult de 3k voturi pozitive.

Simțiți-vă liber să împărtășiți feedback-ul și întrebările dvs. Codificare fericită.

Urmează-mă pe mine Mediu și Stare de nervozitate pentru actualizări.