flux de joc Android Studio apăsând acasă. Procese și fire

Când o componentă de aplicație este lansată când nu există alte componente care rulează, sistemul Android începe un nou proces Linux pentru aplicație cu un singur fir de execuție. În mod implicit, toate componentele unei singure aplicații rulează în același proces și fir (numit „fir principal”). Dacă o componentă de aplicație rulează în timp ce există un proces pentru acea aplicație (deoarece există o altă componentă din aplicație), atunci componenta rulează în acel proces și utilizează același fir de execuție. Cu toate acestea, puteți organiza execuția altor componente ale aplicației în procese separate și puteți crea un fir suplimentar pentru orice proces.

Acest document discută cum funcționează procesele și firele de execuție într-o aplicație Android.

Procesele

În mod implicit, toate componentele unei singure aplicații rulează în același proces și majoritatea aplicațiilor nu ar trebui să modifice acest comportament. Cu toate acestea, dacă trebuie să controlați procesului căruia îi aparține o anumită componentă, puteți face acest lucru în fișierul manifest.

Intrarea manifest pentru fiecare tip de element de componentă - și - acceptă un atribut android:process care vă permite să specificați procesul în care ar trebui să ruleze componenta. Puteți seta acest atribut astfel încât fiecare componentă să ruleze în propriul proces sau astfel încât numai unele dintre componente să partajeze același proces. De asemenea, puteți configura procesul android:process pentru a rula componente din aplicații diferite în același proces, atâta timp cât aplicațiile au același ID de utilizator Linux și se conectează cu același certificat.

  • Proces gol

    Un proces care nu conține nicio componentă activă a aplicației. Singurul motiv pentru a păstra acest tip de proces este pentru stocarea în cache, care îmbunătățește timpul de rulare următor al unei componente din acel proces. Sistemul elimină adesea aceste procese pentru a distribui uniform toate resursele sistemului între memoria cache a proceselor și memoria cache a nucleului de bază.

  • Sistemul Android clasifică procesul drept maxim nivel inalt pe baza importanţei componentelor active în proces la momentul curent. De exemplu, dacă un proces conține un serviciu și o activitate vizibilă, procesul este considerat vizibil și nu un proces de serviciu.

    În plus, nivelul unui proces poate fi promovat deoarece există și alte procese care depind de el. De exemplu, un proces care servește un alt proces nu poate avea un nivel mai mic decât nivelul procesului deservit. De exemplu, dacă un furnizor de conținut în procesul A deservește un client în procesul B sau dacă un proces de serviciu A este asociat cu o componentă din procesul B, procesul A este întotdeauna considerat cel puțin la fel de important ca procesul B.

    Deoarece un proces care rulează un serviciu are un preț mai mare decât un proces cu activități de fundal, o activitate care începe o operație de lungă durată poate începe pentru acea operație în loc să creeze doar un fir de lucru, mai ales dacă activitatea rulează mai mult decât activitatea. De exemplu, o activitate care încarcă o imagine pe un site web trebuie să pornească un serviciu pentru a efectua încărcarea, astfel încât încărcarea să poată continua în fundal chiar și după ce utilizatorul iese din activitate. Utilizarea unui serviciu asigură că operațiunea va avea cel puțin prioritate de „proces de serviciu”, indiferent de ce se întâmplă cu acțiunea. Din același motiv, receptorii ar trebui să folosească servicii și nu doar operațiuni cu fire care durează mult timp pentru a fi finalizate.

    cursuri

    Când o aplicație pornește, sistemul creează un fir de execuție pentru aplicație, care se numește „master”. Acest fir este foarte important, deoarece este responsabil pentru trimiterea evenimentelor către widget-urile interfeței de utilizator corespunzătoare, inclusiv evenimente reprezentare grafică. Este, de asemenea, firul în care aplicația interacționează cu componentele din setul de instrumente Android UI (componente din pachete și). În esență, firul principal este ceea ce se numește uneori firul UI.

    Sistem nu creează un fir separat pentru fiecare instanță de componentă. Toate componentele care rulează în același proces sunt instanțiate pe firul UI și apelurile de sistem ale fiecărei componente sunt trimise din acel fir. Prin urmare, metodele care răspund la apelurile inverse ale sistemului (cum ar fi o metodă de raportare a acțiunilor utilizatorului sau o metodă de apel invers ciclu de viață) sunt întotdeauna executate pe firul UI al procesului.

    De exemplu, atunci când utilizatorul apasă un buton de pe ecran, firul UI al aplicației dvs. trimite un eveniment de clic către widget, care la rândul său setează butonul la starea apăsată și trimite o solicitare de anulare la coada de evenimente. Firul de execuție UI scoate din coadă cererea și notifică widget-ul că ar trebui să fie redată din nou.

    Când aplicația o face muncă intensivă ca răspuns la acțiunile utilizatorului, acest model cu un singur fir poate prezenta performanțe slabe dacă aplicația nu este implementată corect. Adică, dacă totul se întâmplă pe firul UI, efectuarea de operațiuni de lungă durată, cum ar fi accesul la rețea sau interogările la baza de date, va bloca întreaga interfață de utilizare. Când un fir este blocat, niciun eveniment nu poate fi procesat, inclusiv evenimentele de modificare a afișajului. Din punctul de vedere al utilizatorului, aplicația pare să fie agățată. Mai rău, dacă firul UI este blocat mai mult de câteva secunde (în prezent aproximativ 5 secunde), este afișată infama „casetă de dialog”. Utilizatorul nemulțumit poate părăsi aplicația și o poate șterge.

    În plus, Android UI Toolkit nu este sigur pentru fire. Prin urmare, nu ar trebui să lucrați la interfața cu utilizatorul din firul de lucru. Manipularea interfeței de utilizare trebuie efectuată din firul de execuție a interfeței de utilizare. Astfel, există doar două reguli ale modelului cu un singur thread al Android:

    1. Nu blocați firul UI
    2. Nu accesați setul de instrumente Android UI din afara firului de UI

    Fluxuri de lucru

    Din cauza modelului cu un singur thread descris mai sus, este foarte important ca dinamismul UI al aplicațiilor dvs. să nu blocheze firul UI. Dacă trebuie să efectuați operațiuni care durează ceva timp, asigurați-vă că le efectuați pe fire separate ("de fundal" sau "lucrător").

    De exemplu, mai jos este codul de control al clicului care încarcă o imagine dintr-un fir separat și le afișează într-un widget:

    Public void onClick (Vizualizare v) ( thread nou (nou Runnable () ( public void run () ( Bitmap b = loadImageFromNetwork ("http://example.com/image.png"); mImageView.setImageBitmap(b); ) )).start(); )

    La prima vedere, ar trebui să funcționeze bine, deoarece creează un fir nou pentru a gestiona funcționarea rețelei. Cu toate acestea, încalcă a doua regulă a modelului cu un singur fir: nu accesați setul de instrumente Android UI din afara firului UI- Acest exemplu se modifică din firul de lucru, nu din firul UI. Acest lucru poate duce la un comportament nedefinit și neașteptat, care poate fi dificil de urmărit.

    Pentru a remedia această problemă, Android oferă mai multe modalități de a accesa firul UI din alte fire. Mai jos este o listă de metode utile:

    De exemplu, puteți repara codul de mai sus cu metoda:

    Public void onClick (Vizualizare v) ( nou Thread (new Runnable () ( public void run () ( final Bitmap bitmap = loadImageFromNetwork ("http://example.com/image.png"); mImageView.post(new Runnable() ) ( public void run() ( mImageView.setImageBitmap(bitmap); ) )); ) )).start(); )

    Implementarea este acum sigură pentru fire: operațiunea de rețea este executată dintr-un fir separat, în timp ce rulează din firul UI.

    Cu toate acestea, pe măsură ce complexitatea crește, acest tip de cod poate deveni confuz și dificil de întreținut. Pentru a gestiona interacțiuni mai complexe cu firul de lucru, puteți utiliza o metodă din firul de lucru pentru a gestiona mesajele care provin din firul de UI. Probabil cea mai bună soluție este extinderea clasei, ceea ce facilitează executarea sarcinilor de flux de lucru care trebuie să interacționeze cu interfața cu utilizatorul.

    Folosind AsyncTask

    Metode sigure pentru fire

    În unele situații, metodele implementate pot fi apelate din mai multe fire și, prin urmare, trebuie scrise pentru a fi sigure pentru fire.

    Acest lucru se aplică în primul rând metodelor care pot fi apelate de la distanță, cum ar fi metodele în . Când o invocare a unei metode este implementată într-o clasă care provine din același proces ca și în executarea în, metoda se execută pe firul de execuție al metodei apelante. Cu toate acestea, atunci când apelul provine de la un alt proces, metoda se execută pe un fir de execuție selectat din pool-ul de fire de execuție pe care sistemul îl menține în același proces cu (nu se execută pe firul de execuție al procesului). De exemplu, deoarece o metodă de serviciu va fi apelată din firul UI al procesului de serviciu, metodele implementate pe obiectul care returnează (de exemplu, o subclasă care implementează metode RPC) vor fi apelate din firele din pool. Deoarece un serviciu poate avea mai mulți clienți, mai multe fire de execuție grupate pot folosi aceeași metodă în același timp. Prin urmare, metodele trebuie implementate într-o manieră sigură pentru fire.

    În mod similar, un furnizor de conținut poate primi solicitări de date care provin dintr-un alt proces. Deși clasele ascund detaliile modului în care procesele interacționează, metodele care răspund la aceste solicitări — metodele și metodele — sunt apelate din pool-ul de fire din procesul furnizorului de conținut, nu din procesul de fir de UI. Deoarece aceste metode pot fi apelate din orice număr de fire de execuție în același timp, ele trebuie, de asemenea, implementate într-o manieră sigură pentru fire.

    Interacțiunea procesului

    Sistemul Android oferă un mecanism pentru comunicarea proceselor (IPC) folosind apelul de procedură de la distanță (RPC), în care o metodă este apelată de o activitate sau altă componentă a aplicației, dar executată de la distanță (într-un alt proces), cu toate rezultatele returnate la componenta de apelare. . Aceasta implică descompunerea apelului de metodă și a datelor sale într-un nivel pe care sistemul de operare îl înțelege, trecerea acestuia din procesul local și spațiul de adresă la procesul de la distanță și spațiul de adrese, apoi reasamblarea și reconstruirea apelului. După aceea, valorile returnate sunt transmise în direcția opusă. Sistemul Android conține tot codul pentru implementarea acestor mecanisme IPC, astfel încât să vă puteți concentra pe definirea și implementarea API-ului RPC.

    Pentru a efectua IPC, o aplicație trebuie să fie legată de un serviciu care utilizează . Informații suplimentare sunt prezentate în secțiunea ghid pentru dezvoltatori.


    Thread-urile vă permit să efectuați mai multe sarcini în același timp fără a interfera unul cu celălalt, ceea ce face posibilă utilizarea eficientă a resurselor sistemului. Threadurile sunt folosite atunci când o acțiune de lungă durată nu ar trebui să interfereze cu alte acțiuni. De exemplu, avem un music player cu butoane de redare și pauză. Dacă apăsați butonul de redare și aveți un fișier muzical care rulează într-un flux separat, atunci nu puteți apăsa butonul de pauză până când fișierul este redat complet. Cu firele, puteți ocoli această limitare.

    Folosind fire de fundal

    Pentru a vă asigura că aplicația dvs. rămâne receptivă, este o idee bună să mutați toate operațiunile lente și consumatoare de timp din firul principal al aplicației într-un fir secundar.

    Toate componentele unei aplicații Android, inclusiv activitățile, serviciile și receptorii de intenție de difuzare, încep să ruleze pe firul principal al aplicației. Ca rezultat, operațiunile consumatoare de timp în oricare dintre aceste componente blochează toate celelalte părți ale aplicației, inclusiv serviciile și activitățile din prim-plan.

    Aplicarea firelor de fundal - conditie necesara dacă doriți să evitați caseta de dialog pentru a forța închiderea aplicației. Când o activitate Android nu răspunde la evenimentele introduse de utilizator (cum ar fi apăsarea unui buton) timp de 5 secunde sau receptorul intenției de difuzare nu iese din handler onReceive()în 10 secunde, aplicația este considerată a fi suspendată. Asemenea situații ar trebui evitate cu orice preț. Utilizați fire de execuție pentru toate operațiunile care necesită timp, inclusiv manipularea fișierelor, solicitările de rețea, tranzacțiile cu baze de date și calculele complexe.

    Android oferă mai multe mecanisme pentru mutarea funcționalității în fundal.

    • Activity.runOnUiThread(Rulabil)
    • View.post(Rulabil)
    • View.postDelayed(Rulabil, lung)
    • Manipulatorii
    • AsyncTask

    În timp ce utilizarea AsyncTask este o soluție bună, există momente când trebuie să creați și să gestionați propriile fire de execuție pentru a rula în fundal.

    Java are o clasă standard pe care o puteți folosi astfel:

    New Thread(new Runnable() ( public void run() ( //faceți operațiuni consumatoare de timp )); ) )).start();

    Această metodă este potrivită numai pentru operațiuni legate de timp. Dar nu veți putea actualiza interfața grafică a programului.

    Dacă trebuie să actualizați interfața programului, atunci trebuie să utilizați AsyncTask, așa cum sa discutat mai sus, sau puteți implementa propria clasă care moștenește din utilizarea obiectului manipulator din pachet android.os pentru a sincroniza cu firul GUI înainte de a actualiza UI.

    Puteți crea și gestiona firele secundare cu clasa manipulator, precum și clasele disponibile în spațiul de nume java.lang.Thread. Mai jos este un cadru simplu pentru împingerea operațiunilor într-un fir copil.

    // Această metodă este apelată din firul GUI principal. private void mainProcessing() ( // Aici, sarcinile consumatoare de timp sunt transferate într-un fir de execuție copil. Thread thread = new Thread(null, doBackgroundThreadProcessing, "Background"); thread.start(); ) // Un obiect rulabil care pornește o metodă de a executa sarcini // în fundal. private Runnable doBackgroundThreadProcessing = new Runnable() ( public void run() ( backgroundThreadProcessing(); ) ); // Metodă care efectuează unele acțiuni în fundal. private void backgroundThreadProcessing() ( [ ... Operații consumatoare de timp... ] )

    Aplicație proastă

    Să scriem o aplicație „proastă” care folosește greșit firul principal. Odată scriam un program pentru a număra corbii. De data aceasta vom număra pisicile negre care ne trec în cale. De ce o fac - știința tace. Poate că statisticile colectate vor ajuta la rezolvarea misterului. Să adăugăm un buton și o etichetă text pe ecranul de activitate. Cod pentru clic pe buton.

    Public void onClick(View view) (long endTime = System.currentTimeMillis() + 20 * 1000; while (System.currentTimeMillis()< endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); infoTextView.setText("Сегодня коты перебегали дорогу: " + mCounter++ + " раз"); }

    Pentru a simula munca grea, programul se întrerupe timp de douăzeci de secunde, apoi afișează textul cu numărul de pisici. Dacă apăsați butonul o dată și așteptați douăzeci de secunde, programul va funcționa conform așteptărilor. Dar imaginați-vă că ați apăsat butonul o dată. Programul a fost întrerupt. Tu, fără să aștepți sfârșitul pauzei, ai apăsat din nou butonul. Programul ar trebui să execute comanda dvs., dar comanda anterioară nu a fost încă finalizată și apare un conflict. Încercați să apăsați butonul de mai multe ori cu pauze scurte. La un moment dat, aplicația va îngheța și va afișa un dialog de sistem:

    LA aplicații reale o astfel de fereastră poate enerva utilizatorul și acesta va acorda un rating scăzut aplicației dvs.

    În acest caz, eroarea este cauzată nu de ieșirea textului în eticheta de text, care, apropo, se realizează și în firul principal, ci de clicul în sine. Dacă comentați ultimele două rânduri de cod legate de vizualizare text, atunci eroarea persistă.

    Trebuie să mutați o sarcină care necesită timp într-un fir separat. Pentru a face acest lucru, este creată o instanță a clasei rulabil, care are o metodă alerga(). În continuare, este creat un obiect, în constructorul căruia a fost creat rulabil. După aceea, puteți începe un nou thread folosind metoda start(). Să rescriem exemplul.

    Public void onClick(Vizualizare vizualizare) ( Runnable runnable = new Runnable() ( public void run() ( // Mută ​​codul vechi aici long endTime = System.currentTimeMillis() + 20 * 1000; while (System.currentTimeMillis()< endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } Log.i("Thread", "Сегодня коты перебегали дорогу: " + mCounter++ + " раз"); // Нельзя! // TextView infoTextView = // (TextView) findViewById(R.id.textViewInfo); // infoTextView.setText("Сегодня коты перебегали дорогу: " + mCounter++ + " раз"); } }; Thread thread = new Thread(runnable); thread.start(); }

    Am mutat tot codul la metodă alerga(). Acum puteți face clic pe butonul non-stop. De data aceasta, aplicația își va păstra funcționalitatea. Pentru a vă asigura de acest lucru, înregistrarea a fost adăugată la cod log.i(). Fiecare clic creează un fir nou în care este executat codul. Firele nu interferează unele cu altele și își așteaptă rândul când sistemul le permite să funcționeze.

    Firul principal se mai numește și firul UI. Nume în firul principal, puteți actualiza textul etichetei text. În fluxurile pe care le creăm, acest lucru nu se poate face. Dacă decomentați ultimul exemplu și rulați proiectul, veți primi un mesaj de eroare.

    Avem nevoie de un intermediar între firele create și firul principal de UI. Clasa servește ca un astfel de intermediar. manipulator(numele complet al clasei android.os.Handler, nu confundați). Trebuie să creați o instanță a clasei și să specificați codul care urmează să fie executat.

    Handler handler = new Handler() ( @Override public void handleMessage(Message msg) ( TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); infoTextView.setText("Pisicile au traversat drumul astăzi: " + mCounter++ + " ori "); ));

    După linia de cod cu log.i() adăugați un apel la metoda intermediarului.

    Log.i("Thread", "Astăzi pisicile au traversat drumul: " + mCounter++ + " times"); handler.sendEmptyMessage(0); // Este interzis! // TextView infoTextView = // (TextView) findViewById(R.id.textViewInfo); // infoTextView.setText("Astăzi pisicile au traversat drumul: " + mCounter++ + " ori");

    Firul apelează proxy-ul, care, la rândul său, actualizează interfața. În cazul nostru, mediatorul trimite un mesaj gol din fir.

    Dar se întâmplă ca un fir să primească informații pentru procesare. Mai jos este un exemplu simplificat.

    Public void onClick(Vizualizare vizualizare) ( Runnable runnable = new Runnable() ( public void run() ( Message msg = handler.obtainMessage(); Bundle bundle = new Bundle(); SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm: ss MM/dd/aaaa", Locale.US); String dateString = dateFormat.format(new Date()); bundle.putString("Key", dateString); msg.setData(bundle); handler.sendMessage(msg) ; ) ); Thread thread = nou Thread (rulabil); thread.start(); ) Handler handler = new Handler()( @Override public void handleMessage(Message msg) ( Bundle bundle = msg.getData(); String date = bundle.getString("Cheie"); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); infoTextView.setText(data); ) );

    Pornirea unui thread

    Să presupunem că ne dezvoltăm propriul jucător. Avem un buton Joaca care denumeşte metoda Joaca() a reda muzica:

    Buton playButton = (Button) findViewById(R.id.play); playButton.setOnClickListener(new View.OnClickListener()) ( public void onClick(View v) (play(); // apel play ) )

    Acum să rulăm metoda pe alt fir. Mai întâi, este creat un nou thread. Următoarele descriu obiectul rulabilîn constructorul de fir. Și în interiorul firului creat numim metoda noastră Joaca(). Și în sfârșit, începem firul.

    Thread myThread = new Thread(// creează un nou thread new Runnable() ( // declară obiectul Runnable în constructor public void run() ( play(); // apelează metoda play ) ));

    linişti pârâul

    Uneori este necesar să suspendați temporar un fir („puneți-l la somn”):

    // sleep timp de 2 secunde (în milisecunde) myThread.sleep(2000);

    Prioritatea firului

    Pentru a seta prioritatea unui proces, utilizați metoda stabilește prioritatea(), care este apelat înainte de a începe firul. Valoarea priorității poate varia de la Thread.MIN_PRIORITY (1) la Thread.MAX_PRIORITY (10):

    MyThread.setPriority(10); myThread.start();

    Anulați execuția fluxului

    Firul are o metodă Stop(), dar utilizarea sa nu este recomandată deoarece lasă aplicația într-o stare nedeterminată. De obicei se folosește această abordare:

    Dacă (myThread != null) ( Thread dummy = myThread; myThread = null; dummy.interrupt(); )

    Există o altă modalitate, când toate firele de execuție sunt declarate demoni. În acest caz, toate firele de execuție care rulează vor fi încheiate automat când firul principal al aplicației se termină:

    MyThread.setDaemon(true); myThread.start();

    Urmează acest ghid pentru a avea un ecran de încărcare în programul meu. LA ghid de studiu spune că activitatea mea ar trebui să Sleep() cu comanda Sleep(), totuși nu recunoaște funcția Sleep() ca o funcție și îmi dă o eroare întreabă dacă vreau să creez o metodă Sleep().

    http://androidcookbook.com/Recipe.seam;jsessionid=4DBCC1688B51DB16A2A40A86E135D361?recipeId=1599

    Iată un exemplu de cod:

    Clasa publică LoadingScreenActivity extinde Activitatea ( //Introduceți o întârziere privat final int WAIT_TIME = 2500; @Override protected void onCreate(Bundle savedInstanceState) ( // TODO Metoda generată automat stub super.onCreate(savedInstanceState); System.out.printl Ecranul LoadingScreenActivity a început"); setContentView(R.layout.loading_screen); findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE); new Handler().postDelayed(new Runnable()( @Override public void run()) ( //Simularea unei sarcini de lungă durată this.Sleep(1000); System.out.println(„Mergerea la datele de profil”); /* Creați o intenție care va porni activitatea ProfileData. */ Intenția mainIntent = new Intent( LoadingScreenActivity.this,ProfileData.class); LoadingScreenActivity.this.startActivity(mainIntent); LoadingScreenActivity.this.finish(); ) ), WAIT_TIME); ) )

    Puteți utiliza una dintre următoarele metode:

    Thread.sleep(timeInMills);

    Sau

    SystemClock.sleep(timeInMills);

    SystemClock.sleep(milisecunde) este o funcție de utilitate foarte asemănătoare cu Thread.sleep(milisecunde), dar ignoră InterruptedException. Utilizați această funcție pentru întârzieri dacă nu utilizați Thread.interrupt() , deoarece va păstra starea întreruptă a firului de execuție.

    Funcția este Thread.sleep(long) .

    Rețineți, totuși, că nu ar trebui să dormiți pe firul UI.

    Dacă utilizați Handlers, rețineți că handler-ul este creat pe firul în care rulează . Așadar, apelarea unui nou Handler().post(... pe firul de execuție UI va executa executabilul pe firul UI, inclusiv această „operație de lungă durată”. Avantajul este că puteți crea un handler pentru firul UI pe care îl puteți utiliza Mai târziu, așa cum se arată mai jos.

    Pentru a include o operațiune de lungă durată pe un fir de execuție de fundal, trebuie să creați un fir în jurul fișierului rulabil, așa cum se arată mai jos. Acum, dacă doriți să actualizați interfața de utilizare după finalizarea operațiunii de lungă durată, trebuie să o publicați în firul de execuție cu un handler.

    Rețineți că această funcționalitate este perfectă pentru AsyncTask, ceea ce va face ca acest lucru să arate mult mai curat decât șablonul de mai jos. Cu toate acestea, am inclus acest lucru pentru a arăta modul în care handlerele, firele și fișierele gestionate sunt legate.

    Clasa publică LoadingScreenActivity extinde Activitatea ( //Introduceți o întârziere privat final int WAIT_TIME = 2500; handler privat uiHandler; @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); uiHandler = new Handler(); la acest handler va rula pe UI Thread System.out.println(„Ecranul LoadingScreenActivity a început”); setContentView(R.layout.loading_screen); findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE); Runnable onUi = new Runnable() ( @Override public void run() ( // aceasta va rula pe firul principal de UI Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class); LoadingScreenActivity.this.startActivity(mainIntent); LoadingScreenActivity.this .finish(); )); Fundal rulabil = new Runnable() ( @Override public void run() ( // Aceasta este întârzierea Thread.Sleep(WAIT_TIME); // Aceasta va rula pe un fir de fundal //Simulând un sarcină de lungă durată Thread.Sleep(1000);System.out.println(„Merg la P Date de profil"); uiHandler.post(onUi); )); nou Thread(fundal).start(); )

    Metoda Thread.sleep() poate fi utilizată pentru a suspenda execuția firului de execuție curent pentru o anumită perioadă de timp în milisecunde. Valoarea milisecunde a argumentului nu poate fi negativă sau va genera o excepție IllegalArgumentException.

    Există o altă metodă sleep (long millis, int nanos) care poate fi utilizată pentru a întrerupe execuția firului curent pentru milisecunde și nanosecunde specificate. Valoarea validă de nano secundă este între 0 și 999999.

    InterruptedException este aruncată dacă orice fir a întrerupt firul curent. Starea întreruptă a firului curent este ștearsă atunci când apare această excepție.

    Anunț:

    Sleep public static void (milis lung) aruncă InterruptedException

    Cum funcționează Thread Sleep?

    Thread.sleep() interacționează cu planificatorul firului de execuție pentru a pune firul curent într-o stare de repaus pentru perioada de timp specificată. Când trece timpul de așteptare, starea firului de execuție se schimbă într-o stare rulabilă și așteaptă ca CPU să se execute în continuare.

    Astfel, timpul real de așteptare al firului de execuție curent depinde de planificatorul firului de execuție, care face parte din sistemul de operare.

    Exemplu de somn al firelor în Java

    Iată unde Thread.sleep() este folosit pentru a opri firul principal cu 2 secunde.

    Pachetul com.journaldev.threads; clasă publică ThreadSleep ( public static void main(String args) aruncă InterruptedException (pornire lungă = System.currentTimeMillis(); Thread.sleep(2000); System.out.println("Timp de somn în ms = "+(System.currentTimeMillis(); )-start)); ) )

    Dacă rulați acest program, veți observa că expirarea firului de execuție pe care o imprimă este puțin mai mare de 2000. Acest lucru este cauzat de modul în care funcționează modul de așteptare al firului de execuție și de implementarea particulară a planificatorului de fire în sistemul de operare.

    Este important să știi asta

    • Suspend întotdeauna execuția firului curent.
    • Firul real „dormite” înainte de a se trezi, iar timpul de execuție depinde de temporizatoarele și programatoarele de sistem.
    • Un fir adormit nu blochează firul curent.
    • Orice alt fir poate întrerupe firul curent în timpul somnului, caz în care este lansată o excepție InterruptedException.

    Un alt exemplu folosind metoda java.lang.Thread.sleep().

    Pachetul com.tutorial; import java.lang.*; clasa publică ThreadDemo implementează Runnable ( Thread t; public void run() ( pentru (int i = 10; i

    Să compilam și să rulăm programul, aceasta va da următorul rezultat:
    Firul-0 10
    firul-1 10
    Firul-0 11
    firul-1 11
    Firul-0 12
    firul-1 12

    Evaluează articolul

    Estima

    În timp ce creați aplicatie de mobil„Bună ziua, lume” puțin mai complicată necesită aproape sigur descărcarea ceva de pe Web sau citirea unui fișier de pe un disc. Pentru funcționarea stabilă a programului în ansamblu, aceste acțiuni trebuie efectuate în fire separate. De ce, când și cum să generați fire noi în Android - veți afla despre acest lucru în acest articol.

    Procese și fire

    Înainte de a ne ocupa de API-ul Android, să ne amintim ce structură are acest sistem de operare. Se bazează pe nucleul Linux, care implementează mecanismele de bază inerente tuturor sistemelor * nix. Nucleul conține module concepute pentru lucru la nivel scăzut: interacțiunea cu hardware-ul, organizarea memoriei, sistemul de fișiere și așa mai departe.

    În lumea Linux, fiecare program care rulează este separat proces. Fiecare proces are un număr unic și propriul „teritoriu” - un spațiu de adrese virtual care conține toate datele procesului. curgere același este un set de instrucțiuni în interiorul unui program (proces) care rulează, care poate fi executat separat. Un thread nu are propriul său identificator unic și spațiu de adresă - moștenește toate acestea de la procesul părinte și le partajează cu alte fire.

    Distribuirea în masă pe Google Play a aplicațiilor care au probleme cu scurgerile de memorie va face utilizatorii să simtă în mod rezonabil că „Android este lent”

    Această stare de fapt duce la faptul că din exterior nu se știe cum merge viața în interiorul procesului, dacă există fire și câte dintre ele - pentru sistemul de operare și alte procese aceasta este o structură atomică cu un identificator unic. Prin urmare, sistemul de operare poate manipula numai procesul și numai procesul care le-a creat gestionează firele. În general, lumea interioara sisteme de operare este foarte interesant, așa că sfătuiesc cititorii să citească ceva din literatura clasică pe Linux.

    Când procesoarele cu mai multe nuclee au apărut în computere (și după ele în tablete și telefoane), programatorii au introdus un planificator de sarcini în sistemul de operare. Un astfel de planificator distribuie independent sarcina pe toate nucleele procesorului, executând blocuri de cod în paralel sau asincron și, prin urmare, îmbunătățește performanța. La început, marketerii chiar vindeau computere cu sloganul „Două nuclee – de două ori mai rapid”, dar, din păcate, nu corespunde realității.

    În Android, este responsabilitatea programatorului să creeze fire și procese noi peste tot. Toate operațiunile care pot dura mai mult de câteva secunde trebuie efectuate pe fire separate. În caz contrar, vor exista întârzieri în redarea interfeței și utilizatorului i se va părea că aplicația „se îngheață”.

    În general, esența programării cu mai multe fire este de a folosi toate resursele dispozitivului cât mai mult posibil, sincronizând în același timp rezultatele calculelor. Acest lucru nu este atât de ușor cum ar părea la prima vedere, dar creatorii Android au adăugat mai multe clase utile la API care au simplificat foarte mult viața unui dezvoltator Java.

    Fire în Android

    O aplicație care rulează pe Android are propriul proces și cel puțin un fir - așa-numitul fir principal. Dacă aplicația are elemente vizuale, atunci în acest thread este lansat un obiect din clasa Activity, care este responsabil de desenarea interfeței (interfața utilizator, UI) pe afișaj.

    Activitatea principală ar trebui să aibă cât mai puține calcule posibil, singura sa sarcină este să afișeze interfața de utilizare. Dacă firul principal este ocupat cu numărarea numărului pi, atunci va pierde contactul cu utilizatorul - până când numărul nu va fi numărat, Activitatea nu va putea procesa solicitările utilizatorilor și din lateral va părea că aplicația s-a blocat. Dacă așteptarea durează puțin mai mult de câteva secunde, sistemul de operare Android va observa acest lucru și utilizatorul va vedea un mesaj ANR (aplicația nu răspunde) cu o sugestie pentru a forța închiderea aplicației.


    Nu este dificil să primiți un astfel de mesaj - este suficient să începeți să lucrați cu sistemul de fișiere, rețea, criptografie și așa mai departe în firul principal. După cum înțelegeți, aceasta este o situație foarte proastă, care nu trebuie repetată în modurile obișnuite ale aplicației.

    Thread și rulabil

    Clasa de bază pentru fire de execuție în Android este clasa Thread, care are totul pregătit pentru a crea un thread. Dar pentru a face ceva în interiorul unui fir nou, trebuie să împachetați datele într-un obiect din clasa Runnable. Thread, după ce a primit un obiect din această clasă, va executa imediat metoda run.

    Clasa publică MyRunnable implementează Runnable ( String goal; public MyRunnable(String goal) ( this.goal=goal; ) @Override public void run() ( getData(goal); ) ) ... MyRunnable runnable = new MyRunnable("do_smth" ); Thread nou (rulabil).start();

    Dar, cu o astfel de organizare, este dificil să utilizați întreaga putere a firelor suplimentare - nu puteți nici să schimbați sarcina, nici să priviți rezultatul calculelor. Deși toate acestea se întâmplă într-un singur spațiu de adresă, nu există nicio modalitate ca un dezvoltator Java să obțină pur și simplu resursele thread-urilor învecinate.

    looper

    Ar fi grozav să poți transfera date dintr-un flux în altul. Pe Android, ca orice sistem Linux, acest lucru este posibil. Una dintre modalitățile disponibile în Android este creați o coadă de mesaje(MessageQueue) într-un fir. La o astfel de coadă pot fi adăugate joburi din alte fire de execuție; joburile pot fi variabile, obiecte sau o bucată de cod pentru execuție (Runnable).

    Mesajul mesaj = mesaj nou(); Bundle mBundle = Bundle nou(); mBundle.putString("KEY", "textMessage"); msg.setData(mBundle);

    Pentru a organiza o coadă, trebuie să utilizați clasele Handler și Looper: prima este responsabilă de organizarea cozii, iar a doua într-o buclă nesfârșită verifică dacă există sarcini noi pentru firul de execuție.

    Clasa publică MyLooper extinde Thread ( număr întreg; handler public mHandler; @Override public void run() ( Looper.prepare(); mHandler = new Handler() ( @Override public void handleMessage(Message msg) ( // procesează mesajele primite aici Log.e("Fire", "#"+număr + ": "+msg.getData().getString("CHEIE")); )); Looper.loop(); ) )

    Pornirea unui astfel de fir urmează un model similar - crearea unui nou obiect și apelarea metodei de pornire.

    MyLooper myLooper = new MyLooper(); myLooper.start();

    După executarea acestei metode, va fi creat un nou thread, care va căpăta viață proprie. Și asta înseamnă că inițializarea variabilelor și crearea obiectelor vor merge deja în paralel cu acele apeluri care sunt înfundate în rândurile următoare după comanda myLooper.start(). Prin urmare, înainte de a accesa coada într-un fir nou, trebuie să așteptați puțin - este posibil ca obiectul handler să nu existe încă.

    Dacă (myLooper.hanlder!=null) (myLooper.mHandler.sendMessage(msg); )

    AsynkTask

    Când încărcați sau calculați ceva în fundal, ar fi bine nu numai să obțineți rezultate, ci și să puteți afișa informații despre progres pentru utilizator. Desigur, toate acestea le puteți face singuri folosind coada de mesaje, dar dezvoltatorii Android ne-au făcut viața mai ușoară și aici prin crearea clasei AsyncTask.

    Este disponibil în continuare numai pentru membri

    Opțiunea 1. Alăturați-vă comunității „site” pentru a citi toate materialele de pe site

    Calitatea de membru al comunității în perioada specificată vă va oferi acces la TOATE materialele Hacker, vă va crește reducerea la economii personale și vă va permite să acumulați rating profesional Scor Xakep!

    airsoft-unity.ru - Portal minier - Tipuri de afaceri. Instrucțiuni. Companii. Marketing. taxe