Як зробити свій бізнес успішним
  • Головна
  • Безготівкові
  • Андроїд студії ігровий потік натискання додому. Процеси та потоки. Використання фонових потоків

Андроїд студії ігровий потік натискання додому. Процеси та потоки. Використання фонових потоків

Я слідую цьому посібнику, щоб мати екран завантаження в моїй програмі. У навчальному посібникуговориться, що моя активність повинна Sleep() за допомогою команди Sleep(), проте вона не розпізнає функцію Sleep() як функцію і надає мені помилку, питаючи, чи хочу я створити метод Sleep().

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

Ось приклад коду:

Public class LoadingScreenActivity extends Activity ( //Introduce an delay private final int WAIT_TIME = 2500; @Override protected void onCreate(Bundle savedInstanceState) ( // TODO Auto-generated метод stub super.onCreate(saved. LoadingScreenActivity screen started"); setContentView(R.layout.loading_screen); findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE); ( //Simulating a long running task this.Sleep(1000); System.out.println("Going to Profile Data"); /* Create an Intent that will start the ProfileData-Activity. */ Intent mainIntent = new Intent( LoadingScreenActivity.this,ProfileData.class); LoadingScreenActivity.this.startActivity(mainIntent);

Ви можете використовувати один із таких методів:

Thread.sleep(timeInMills);

Або

SystemClock.sleep(timeInMills);

SystemClock.sleep(milliseconds) – це функція утиліти, дуже схожа на Thread.sleep(milliseconds), але ігнорує InterruptedException. Використовуйте цю функцію для затримок, якщо ви не використовуєте Thread.interrupt() , оскільки вона збереже перерваний стан потоку.

Функція - Thread.sleep (long).

Зверніть увагу, однак, що ви не повинні виконувати сплячий режим у потоці інтерфейсу користувача.

Якщо ви використовуєте Handlers, майте на увазі, що обробник створюється у потоці, де він виконується . Тому виклик new Handler().post(... в потоці інтерфейсу користувача буде виконувати runnable в потоці інтерфейсу користувача, включаючи цю «тривалу операцію». Перевага полягає в тому, що ви можете створити обробник для потоку інтерфейсу користувача, який ви можете використовувати Пізніше, як показано нижче.

Щоб увімкнути тривалу операцію у фоновий потік, вам потрібно створити потік навколо runnable, як показано нижче. Тепер, якщо ви хочете оновити інтерфейс користувача після завершення тривалої операції, вам необхідно опублікувати його в потоці інтерфейсу користувача за допомогою обробника.

Зверніть увагу, що ця функціональність ідеально підходить для AsyncTask, що зробить цей вид набагато чистішим, ніж шаблон нижче. Однак я включив це, щоб показати, як пов'язані обробники, потоки та керовані файли.

Public class LoadingScreenActivity extends Activity ( //Introduce a delay private final int WAIT_TIME = 2500; private Handler uiHandler; @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState) this handler will run on the UI Thread System.out.println("LoadingScreenActivity screen started"); new Runnable() ( @Override public void run() ( // this will run on the main UI thread Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class); LoadingScreenActivity.this.startActivity(mainIntent); LoadingScreenActivity.this.startActivity(mainIntent)); .finish(); ) );Runnable background = new Runnable() long running task Thread.Sleep(1000); uiHandler.post(onUi); ))); new Thread(background).start(); )

Коли компонент програми запускається за відсутності інших працюючих компонентів, Android запускає новий процес Linux для програми з одним потоком виконання. За замовчуванням всі компоненти однієї програми працюють в одному процесі та потоці (називається «головним потоком»). Якщо компонент програми запускається за наявності процесу для цієї програми (оскільки існує інший компонент із програми), тоді компонент запускається в цьому процесі і використовує той же потік виконання. Однак можна організувати виконання інших компонентів програми в окремих процесах та створювати додатковий потік для будь-якого процесу.

У цьому документі обговорюється робота процесів та потоків у додатку Android.

Процеси

За замовчуванням всі компоненти однієї програми працюють в одному процесі, і більшість програм не повинні змінювати цю поведінку. Однак, якщо необхідно контролювати, до якого процесу належить певний компонент, можна зробити це у файлі маніфесту.

Запис маніфесту кожного типу елементів компонента — , і — підтримує атрибут android:process , що дозволяє задавати процес, у якому слід виконувати цей компонент. Цей атрибут можна встановити так, щоб кожен компонент виконувався у власному процесі, або так, щоб тільки деякі компоненти спільно використовували один процес. Можна також налаштувати процес android:process так, щоб компоненти різних програм виконувались в одному процесі, за умови, що програми спільно використовують один ідентифікатор користувача Linux і виконують вхід з одним сертифікатом.

  • Порожній процес

    Процес, що не містить жодних компонентів активної програми. Єдина причина зберігати процес такого типу – це кешування, яке покращує час наступного запуску компонента у цьому процесі. Система часто видаляє ці процеси для рівномірного розподілу всіх системних ресурсів між кешем процесу та кешем базового ядра.

  • Система Android відносить процес до максимально високого рівняз урахуванням важливості компонентів, активних у процесі у час. Наприклад, якщо процес містить службову та видиму дію, процес вважається видимим, а не службовим процесом.

    Крім того, рівень процесу може бути підвищений, оскільки є інші, залежні від нього процеси. Наприклад, процес, який обслуговує інший процес, не може мати рівень нижче рівня обслуговуваного процесу. Наприклад, якщо постачальник контенту в процесі A обслуговує клієнта в процесі B або службовий процес A пов'язаний із компонентом у процесі B, процес A завжди вважається не менш важливим, ніж процес B.

    Так як процес, що виконує службу, оцінюється вище процесу з фоновими діями, дія, що запускає довготривалу операцію, може запустити для цієї операції, а не просто створити робочий потік, особливо у випадку, якщо операція триватиме довше. Наприклад, дія, яка завантажує зображення на веб-сайт, повинна запустити службу для завантаження, так що завантаження може тривати у фоновому режимі навіть після виходу користувача з дії. Використання служби гарантує, що операція матиме пріоритет не нижче за «службовий процес», незалежно від того, що відбувається з дією. З цієї ж причини ресивери повинні використовувати служби, а не просто ставити в потік операції, що вимагають багато часу для виконання.

    Потоки

    При запуску програми система створює потік виконання програми, який називається «головним». Цей потік дуже важливий, оскільки він відповідає за диспетчеризацію подій на віджети відповідного інтерфейсу користувача, включаючи події графічного уявлення. Він також є потоком, в якому додаток взаємодіє з компонентами з набору інструментів інтерфейсу користувача Android (компонентами з пакетів і ). По суті, головний потік - це те, що іноді називають потоком інтерфейсу користувача.

    Система нестворює окремий поток для кожного екземпляра компонента. Всі компоненти, які виконуються в одному процесі, створюють екземпляри в потоці інтерфейсу користувача, і системні виклики кожного компонента відправляються з цього потоку. Тому методи, які відповідають на системні зворотні дзвінки (такі як метод для повідомлення про дії користувача або метод зворотного дзвінка) життєвого циклу), завжди виконуються в потоці інтерфейсу користувача процесу.

    Наприклад, коли користувач натискає кнопку на екрані, потік інтерфейсу користувача вашої програми відправляє подію натискання в віджет, який, в свою чергу, встановлює кнопку в натиснений стан і відправляє запит на анулювання в чергу подій. Потік інтерфейсу користувача виключає запит з черги і повідомляє віджет, що він повинен відобразитися повторно.

    Коли програма виконує інтенсивну роботу у відповідь на дії користувача, ця одиночна модель потоку може показувати погану продуктивність, якщо програма реалізована неправильно. Тобто, якщо все відбувається в потоці інтерфейсу користувача, виконання довготривалих операцій, таких як мережевий доступ або запити до бази даних, буде блокувати весь інтерфейс користувача. Коли потік заблокований, не можуть оброблятися жодні події, включаючи зміни відображення. З точки зору користувача програма виглядає завислим. Гірше того, якщо потік інтерфейсу користувача заблокований більше кількох секунд (в даний час близько 5 секунд), відображається сумно відоме діалогове вікно ». Після цього незадоволений користувач може вийти з вашої програми та видалити його.

    Крім того, набір інструментів інтерфейсу користувача Android неє потокобезпечним. Тому, ви не повинні працювати з інтерфейсом користувача з робочого потоку. Маніпуляції з інтерфейсом користувача необхідно виконувати з потоку інтерфейсу користувача. Таким чином, існує лише два правила однопоточної моделі Android:

    1. Не блокуйте потік інтерфейсу користувача
    2. Не звертайтеся до набору інструментів інтерфейсу користувача Android зовні потоку інтерфейсу користувача

    Робочі потоки

    Внаслідок описаної вище однопоточної моделі для динамічності користувальницького інтерфейсу ваших додатків дуже важливо не блокувати потік інтерфейсу користувача. Якщо потрібно виконувати операції, що займають деякий час, обов'язково виконуйте їх в окремих потоках (фонових або робочих потоках).

    Наприклад, нижче наведено код контролю натискань, який завантажує зображення з окремого потоку і відображає їх у віджеті:

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

    На перший погляд він повинен працювати добре, тому що він створює новий потік для обробки мережевої операції. Однак він порушує друге правило однопоточної моделі: не звертайтеся до набору інструментів інтерфейсу користувача Android зовні потоку інтерфейсу користувача— цей приклад змінює з робочого потоку, а не з потоку інтерфейсу користувача. Це може призвести до невизначеної та непередбачуваної поведінки, відстежити яку буде важко.

    Для усунення цієї проблеми Android пропонує кілька шляхів доступу до потоку інтерфейсу користувача з інших потоків. Нижче наведено список корисних методів:

    Наприклад, можна виправити наведений вище код за допомогою методу:

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

    Тепер реалізація є потокобезпечною: мережна операція виконується з окремого потоку, тоді як працює з потоку інтерфейсу користувача.

    Однак у міру зростання складності код такого типу може ставати заплутаним і складним для підтримки. Щоб обробляти більш складні взаємодії з робочим потоком, можна використовувати метод у робочому потоці для обробки повідомлень, що надходять з потоку інтерфейсу користувача. Ймовірно, самим найкращим рішеннямє розширення класу , яке спрощує виконання завдань робочого потоку, які повинні взаємодіяти з інтерфейсом користувача.

    Використання AsyncTask

    Потокобезпечні методи

    У деяких ситуаціях реалізовані методиможуть викликатися з кількох потоків і, отже, мають бути написані із збереженням потокобезпеки.

    Насамперед це відноситься до методів, які можна викликати віддалено, наприклад, до методів . Коли виклик методу реалізується в класі , що відбувається з того ж процесу, в якому виконується метод виконується в потоці викликаючого методу. Однак, коли виклик відбувається з іншого процесу, метод виконується в потоці, вибраному з пула потоків, які система підтримує в тому ж процесі, що і (він не виконується в потоці інтерфейсу користувача процесу). Наприклад, оскільки метод служби буде викликатися з потоку інтерфейсу користувача процесу служби, методи, реалізовані в об'єкті, який повертає (наприклад, підклас, який реалізує методи RPC), будуть викликатися з потоків в пулі. Так як служба може мати кілька клієнтів, кілька потоків з пулу можуть одночасно використовувати один і той самий метод. Тому методи мають бути реалізовані із збереженням потокобезпеки.

    Аналогічно постачальник контенту може отримувати запити даних, що походять з іншого процесу. Хоча класи і приховують подробиці управління взаємодією процесів, методи , які відповідають ці запити, —методи , і —викликаються з пулу потоків у процесі постачальника контенту, а чи не у процесі потоку користувальницького інтерфейсу. Оскільки ці методи можуть викликатись з будь-якої кількості потоків одночасно, вони також повинні бути реалізовані із збереженням потокобезпеки.

    Взаємодія процесів

    Система Android пропонує механізм взаємодії процесів (IPC) за допомогою віддаленого виклику процедури (RPC), при якому метод викликається дією або іншим компонентом програми, але виконується віддалено (в іншому процесі) з поверненням усіх результатів компоненту, що викликає. Це спричиняє розкладання виклику методу та його даних рівня, зрозумілого операційній системі, передачу його з локального процесу та адресного простору віддаленому процесу та адресному простору, а потім повторне складання та відновлення виклику. Після цього повернуті значення передаються у зворотному напрямку. Система Android містить усі коди для виконання цих механізмів IPC, тому ви можете зосередитися на визначенні та реалізації програмного інтерфейсу RPC.

    Для виконання IPC програма має бути прив'язана до служби за допомогою методу. Для отримання додаткових відомостей див. посібник для розробників.

    Метод Thread.sleep() можна використовувати для призупинення виконання поточного потоку на вказаний час у мілісекундах. Значення аргументу в мілісекундах не може бути негативним, інакше воно видає виняток IllegalArgumentException.

    Існує ще один метод sleep(long millis, int nanos), який можна використовувати для зупинення виконання поточного потоку на зазначені мілісекунди та наносекунди. Допустиме значення nano second становить від 0 до 999999.

    InterruptedException виникає, якщо якийсь потік перервав поточний потік. Перерваний стан поточного потоку очищається у разі цього винятку.

    Оголошення:

    Public static void sleep(long millis) throws InterruptedException

    Як працює Thread Sleep?

    Thread.sleep() взаємодіє з планувальником потоку, щоб перевести поточний потік стан очікування протягом зазначеного періоду часу. Після закінчення часу очікування стан потоку змінюється на працездатний стан і очікує ЦП для подальшого виконання.

    Таким чином, фактичний часочікування поточного потоку залежить від планувальника потоку, який є частиною операційної системи.

    Приклад thread sleep на Java

    Ось , в якій Thread.sleep() використовується для затримки часу основного потоку на 2 секунди.

    Package com.journaldev.threads; Public class ThreadSleep ( public static void main(String args) throws InterruptedException ( long start = System.currentTimeMillis(); Thread.sleep(2000); System.out.println("Sleep time in ms = "+(System.currentTimeMillis( )-start));

    Якщо ви запустите цю програму, ви помітите, що час очікування потоку, який вона друкує, трохи більше, ніж 2000. Це викликано тим, як працює режим очікування потоку, та конкретною реалізацією планувальника потоку в операційній системі.

    Важливо знати, що

    • Завжди зупиняє виконання поточного потоку.
    • Фактичний потік «спить» до пробудження, і час виконання залежить від системних таймерів та планувальників.
    • Сплячий потік не блокує поточний потік.
    • Будь-який інший потік може перервати поточний потік в режимі сну, в цьому випадку створюється виняток InterruptedException.

    Ще приклад з використанням методу java.lang.Thread.sleep().

    Package com.tutorial; import java.lang.*; Public class ThreadDemo implements Runnable ( Thread t; public void run() ( for (int i = 10; i

    Давайте скомпілюємо та запустимо програму, це дасть наступний результат:
    Thread-0 10
    Thread-1 10
    Thread-0 11
    Thread-1 11
    Thread-0 12
    Thread-1 12

    Оціни статтю

    Оцінити

    При створенні мобільного додаткутрохи складніше Hello, world майже напевно потрібно скачати щось з Мережі або рахувати файл з диска. Для стабільної роботи програми загалом ці дії мають здійснюватись в окремих потоках. Навіщо, коли і як генерувати нові потоки в Android – про це ти дізнаєшся у цій статті.

    Процеси та потоки

    Перш ніж розбиратися з Android API, пригадаємо, яку структуру має ця ОС. В її основі лежить Linux-ядро, в якому реалізовані базові механізми, притаманні всім *nix-системам. У ядрі зібрані модулі, призначені для низькорівневої роботи: взаємодії із залізом, організації пам'яті, файлової системи тощо.

    У світі Linux кожна запущена програма – це окремий процес. Кожен процес має унікальний номер і власну «територію» - віртуальний адресний простір, в рамках якого містяться всі дані процесу. Потіка - це набір інструкцій усередині запущеної програми (процесу), який може бути виконаний окремо. Потік не має свого унікального ідентифікатора та адресного простору - все це він успадковує від батьківського процесу і ділить з іншими потоками.

    Масове поширення в Google Play додатків, що мають проблеми з витоком пам'яті, резонно викличе у користувачів відчуття, що Android гальмує

    Такий стан справ призводить до того, що з боку невідомо, як протікає життя всередині процесу, чи є там потоки та скільки їх, – для ОС та інших процесів це атомарна структура з унікальним ідентифікатором. Тому ОС може маніпулювати лише процесом, а керує потоками що тільки породив їх процес. Взагалі, внутрішній світ операційних систем дуже цікавий, тому раджу читачам почитати щось із класичної літератури з Linux.

    Коли в комп'ютерах (а слідом за ними – у планшетах та телефонах) з'явилися процесори з кількома ядрами, програмісти впровадили в ОС планувальник завдань. Такий планувальник самостійно розподіляє навантаження по всіх ядер процесора, виконуючи блоки коду паралельно або асинхронно, і тим самим підвищує продуктивність. Спочатку маркетологи навіть продавали комп'ютери з гаслом «Два ядра – у два рази швидше», але, на жаль, насправді він не відповідає.

    В Android програміст зобов'язаний створювати нові потоки і процеси. Усі операції, які можуть тривати більше кількох секунд, повинні виконуватися в окремих потоках. Інакше почнуться затримки у малюванні інтерфейсу і користувачеві здаватиметься, що програма «зависає».

    Взагалі, суть багатопотокового програмування в тому, щоб максимально використовувати всі ресурси пристрою, при цьому синхронізуючи результати обчислень. Це не так легко, як здається, але творці Android додали в API кілька корисних класів, які сильно спростили життя Java-розробнику.

    Потоки в Android

    Запущене в Android додатокмає власний процес і як мінімум один потік - так званий головний потік (main thread). Якщо в програмі є якісь візуальні елементи, то в цьому потоці запускається об'єкт класу Activity, що відповідає за відображення на дисплеї інтерфейсу (user interface, UI).

    У головному Activity має бути якнайменше обчислень, єдине його завдання - відображати UI. Якщо головний потік буде зайнятий підрахунком числа пі, то він втратить зв'язок з користувачем - поки число не дорахувалося, Activity не зможе обробляти запити користувача і збоку здаватиметься, що програма зависла. Якщо очікування триватиме трохи більше пари секунд, ОС Android помітить це і користувач побачить повідомлення ANR (application not responding - «додаток не відповідає») з пропозицією примусово завершити додаток.


    Отримати таке повідомлення нескладно - досить у головному потоці розпочати роботу з файловою системою, мережею, криптографією тощо. Як ти розумієш, це дуже погана ситуація, яка не повинна повторюватися в штатних режимах роботи програми.

    Thread та Runnable

    Базовим класом для потоків Android є клас Thread, в якому вже все готове для створення потоку. Але для того, щоби щось виконати всередині нового потоку, потрібно загорнути дані в об'єкт класу Runnable. Thread, отримавши об'єкт цього класу, відразу виконає метод run .

    Public class MyRunnable implements Runnable ( String goal; public MyRunnable(String goal) ( this.goal=goal; ) @Override public void run() ( getData(goal); ) ) ... MyRunnable runnable=" ); new Thread(runnable).start();

    Але за такої організації складно використовувати всю силу додаткових потоків - не можна ні змінити завдання, ні побачити результат обчислень. Хоча все це відбувається в єдиному адресному просторі, Java-розробник не має можливості просто так отримати ресурси сусідніх потоків.

    Looper

    Було б класно вміти перекидати дані з потоку до іншого. В Android, як і в будь-якій Linux-системі, це можливо. Один з доступних в Android способів – це створити чергу повідомлень(MessageQueue) всередині потоку. У таку чергу можна додавати завдання інших потоків, завданнями можуть бути змінні, об'єкти або шматок коду для виконання (Runnable).

    Message msg = New Message (); Bundle mBundle = New Bundle(); mBundle.putString("KEY", "textMessage"); msg.setData(mBundle);

    Щоб організувати чергу, потрібно скористатися класами Handler та Looper: перший відповідає за організацію черги, а другий у нескінченному циклі перевіряє, чи немає в ній нових завдань для потоку.

    Public class MyLooper extends Thread ( Integer number; public Handler mHandler; @Override public void run() ( Looper.prepare(); mHandler = new Handler() ( @Override public void handle Log.e("Thread", "#"+number + ": "+msg.getData().getString("KEY")); ) ;

    Запуск такого потоку влаштований за схожою схемою - створення нового об'єкта та виклик методу start.

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

    Після виконання цього методу створиться новий потік, який загоїться своїм життям. А це означає, що ініціалізація змінних та створення об'єктів вже йдуть паралельно з тими викликами, які забиті у наступних рядках після команди myLooper.start(). Тому перед зверненням до черги у новому потоці потрібно трохи почекати – об'єкт handler може ще не існувати.

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

    AsynkTask

    Завантажуючи або обчислюючи щось у фоні, добре не тільки отримати результати, але ще й мати можливість виводити користувачеві інформацію про прогрес. Звичайно, все це можна зробити самому за допомогою черги повідомлень, але розробники Android тут спростили нам життя, створивши клас AsyncTask.

    Продовження доступне лише учасникам

    Варіант 1. Приєднайтесь до спільноти «сайт», щоб читати всі матеріали на сайті

    Членство у спільноті протягом зазначеного терміну відкриє тобі доступ до ВСІХ матеріалів «Хакера», збільшить особисту накопичувальну знижку та дозволить накопичувати професійний рейтинг Xakep Score!

    Найкращі статті на тему