Страницы

Поиск по вопросам

Показаны сообщения с ярлыком android-threads. Показать все сообщения
Показаны сообщения с ярлыком android-threads. Показать все сообщения

понедельник, 6 января 2020 г.

Потоки и IntentService

#android #android_service #android_threads


В каком потоке происходит работа IntentService? Вроде как по определению это подкласс
обычного Service, у которого метод onHandleIntent отрабатывает в background потоке:


  Clients send requests through Context.startService(Intent) calls; the
  service is started as needed, handles each Intent in turn using a
  worker thread, and stops itself when it runs out of work.


...


  All requests are handled on a single worker thread -- they may take as
  long as necessary (and will not block the application's main loop),
  but only one request will be processed at a time.


Но правильно ли я понимаю, что всё равно сам IntentService работает в главном (UI)
потоке, и из него уже запускает новый worker/background-поток? И при завершении приложения
IntentService будет убит вместе со всем приложением, до конца выполнится только текущий
метод onHandleIntent, но следующий уже не будет запущен?

К примеру, если в активити есть следующий код:

for (int i = 0; i < 5; i++) {
   Intent intent = new Intent(this, MyIntentService.class);
   this.startService(intent);
}


и приложение завершается, когда весь цикл выполнен, но метод onHandleIntent отработал
только один раз, то больше метод onHandleIntent вызван не будет?

UPD

Например, если говорить об исходном коде класса IntentService:

public abstract class IntentService extends Service {
   ...
   @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    ...
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    ...
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}


Правильно ли я понимаю, что в этом случае (в примере с циклом) метод onStartCommand
выполнится 5 раз, и вызовет 5 раз метод onStart, который с помощью mServiceHandler
помещает intent-ы в очередь, но при завершении main-потока умирает вместе с ним?..
    


Ответы

Ответ 1



В каком потоке происходит работа IntentService? работа IntentService происходит в отдельном Thread, который создается во время создания сервиса, все остальные Message будут поститься на Looper от этого треда, те получается что это SingleQueue. Но правильно ли я понимаю, что всё равно сам IntentService работает в главном (UI)? Не совсем точно. По умолчанию все компоненты одного приложения работают в одном процессе, но вам никто не помешает запустить сервис из другого потока, внутри себя он создаст поток из контекста который вы передадите. Как только процесс завершится поток сервиса умрет. И при завершении приложения IntentService будет убит вместе со всем приложением, до конца выполнится только текущий метод onHandleIntent, но следующий уже не будет запущен? Да. Но подмечу если компоненты одного приложения работают в одном процессе. и приложение завершается, когда весь цикл выполнен, но метод onHandleIntent отработал только один раз, то больше метод onHandleIntent вызван не будет? не факт, здесь работа разных потоков может успеть вызываться, а может нет. Смотря как быстро вы убиваете процесс. Смею предположить если сделать, что-то типо System.exit(0) то не успеет даже 1-раз вызваться. Правильно ли я понимаю, что в этом случае (в примере с циклом) метод onStartCommand выполнится 5 раз, и вызовет 5 раз метод onStart, который с помощью mServiceHandler помещает intent-ы в очередь, но при завершении main-потока умирает вместе с ним?. Да.

Ответ 2



И я решила ещё проверить на практике свои предположения, для этого создала класс, аналогичный IntentService, добавив в методы этого класса только логирование, и добавила логирование в цикл: for (int i = 0; i < 5; i++) { Log.i(LOG_TAG, "Cycle: " + i); Intent intent = new Intent(this, TestService.class); startService(intent); } В результате получила следующий вывод: Cycle: 0 Cycle: 1 Cycle: 2 Cycle: 3 Cycle: 4 IntentServiceWithLog onStartCommand IntentServiceWithLog onStart TestService onHandleIntent IntentServiceWithLog onStartCommand IntentServiceWithLog onStart IntentServiceWithLog onStartCommand IntentServiceWithLog onStart TestService onHandleIntent IntentServiceWithLog onStartCommand IntentServiceWithLog onStart IntentServiceWithLog onStartCommand IntentServiceWithLog onStart TestService onHandleIntent TestService onHandleIntent TestService onHandleIntent И если ещё добавить в эти методы логирование имени потока: Log.i("THREAD", Thread.currentThread().getName()); гипотеза тоже подтверждается: IntentServiceWithLog onStartCommand THREAD: main IntentServiceWithLog onStart THREAD: main TestService onHandleIntent THREAD: IntentService[TestService]

среда, 4 декабря 2019 г.

Android Thread.name

#android #многопоточность #android_threads


Я работаю с потоками в своем проекте. Среди прочих потоков, в двух разных классах
создается две HandlerThread таким вот образом:    

HandlerThread thread = new HandlerThread("ServiceThread", Process.THREAD_PRIORITY_DEFAULT);    


Дальше они стартуются: thread.start();, и я использую их луперы.
И только что я обнаружил, что они создаются с абсолютно одинаковыми именами (первый
параметр в конструкторе - имя).
Мой вопрос состоит в том, могут ли быть проблемы из за того, что у потоков одинаковые
имена? Являются ли имена какими-то идентификаторами для потоков?
    


Ответы

Ответ 1



Не будет проблем. При создании нового HandlerThread вызывается конструктор: public HandlerThread(String name, int priority) { super(name); mPriority = priority; } Идем вглубь и видим if (threadName == null) { this.name = "Thread-" + id; } else { this.name = threadName } Что и есть практическим подтверждением написанного в Javadoc: Каждый поток имеет имя в целях идентификации. Более чем один поток может иметь такое же имя . Если имя не указано , когда создается поток, новое имя генерируется для него.

Ответ 2



Нет, имена в thread не имеют никакого значения кроме удобства тестирования и логирования. Уникальным идентификатором thread будет pid.

Ответ 3



Из оффдока Every thread has a name for identification purposes. More than one thread may have the same name. If a name is not specified when a thread is created, a new name is generated for it. По идее про проблемы ничего не сказано, значит это нормально

вторник, 9 июля 2019 г.

Android приложение перестало работать

Написал приложение, которое принимает JSON с сервера и результат выводит в RecyclerView. Изначально все работало корректно, но через некоторое время стало зависать на ProgressBar в Android 5.0. На эмуляторе Android studio все работает отлично (эмулятор Android 7.1.1). Зависает в фоновом потоке при десериализации JSON
MainActivity.java
public class MainActivity extends AppCompatActivity {
Context context; ProgressBar progressBar; RecyclerView filmView; Activity main;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); main = this; context=this; setContentView(R.layout.activity_main); filmView = (RecyclerView) findViewById(R.id.FilmsList); progressBar = (ProgressBar) findViewById(R.id.progressBar); progressBar.setVisibility(ProgressBar.VISIBLE);
MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start(); }
/** * Класс для обработки Json */ public class MyThread extends Thread{ private final long date=System.currentTimeMillis()/1000L; private final String FILMS_URL ="http://example.com" private String resultJson; private JSONObject jsonObject; private JSONArray js; Adapter adapter; private Films[] films; InputStream inputStream; @Override public void run(){ try { URL url = new URL(FILMS_URL); URLConnection http = url.openConnection(); inputStream = http.getInputStream(); http.connect(); StringBuilder buffer = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { buffer.append(line); } resultJson = buffer.toString(); } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } try { jsonObject = new JSONObject(resultJson); js = jsonObject.getJSONArray("results"); films =new Gson().fromJson(js.toString(), Films[].class); } catch (JSONException e) { e.printStackTrace(); } filmView.post(new Runnable() { @Override public void run() {
filmView.addItemDecoration(new SpacesItemDecoration(50)); filmView.setHasFixedSize(true); adapter = new Adapter(main, context, films); LinearLayoutManager llm = new LinearLayoutManager(main); llm.setOrientation(LinearLayoutManager.VERTICAL); filmView.setLayoutManager(llm); filmView.setAdapter(adapter);
/** * Обработка нажатий */ filmView.addOnItemTouchListener( new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) { Intent intent = new Intent(MainActivity.this, FilmDetails.class); String filmString; GsonBuilder gsonBuilder=new GsonBuilder(); gsonBuilder.registerTypeAdapter(Films.class, new MyTypeAdapter()); gsonBuilder.setPrettyPrinting(); Gson gson=gsonBuilder.create(); filmString =gson.toJson(films[position]); intent.putExtra("films", filmString); //передаём объект как json-строку startActivity(intent); } }) ); } }); } }
public void onProgressClick(View view){ Toast toast=Toast.makeText(this, "loading...", Toast.LENGTH_SHORT); toast.setGravity(Gravity.BOTTOM, 0, 0); toast.show(); } }
в логи пишет это
01-13 13:45:31.464 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 53.907ms 01-13 13:45:33.422 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 5.432ms 01-13 13:45:35.849 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 9256(454KB) AllocSpace objects, 3(47KB) LOS objects, 21% free, 2017KB/2MB, paused 4.327ms total 312.016ms 01-13 13:45:35.876 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 24.495ms 01-13 13:45:35.953 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 34.178ms 01-13 13:45:36.939 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 5.087ms 01-13 13:45:38.017 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 90.718ms 01-13 13:45:39.033 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 106.362ms 01-13 13:45:39.123 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 5725(315KB) AllocSpace objects, 1(16KB) LOS objects, 13% free, 2MB/2MB, paused 3.789ms total 499.241ms 01-13 13:45:39.565 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 140.064ms 01-13 13:45:39.734 1353-1365/com.example.sharafievp.myfilm I/art: Background partial concurrent mark sweep GC freed 8075(378KB) AllocSpace objects, 0(0B) LOS objects, 39% free, 2MB/3MB, paused 2.541ms total 374.222ms 01-13 13:45:39.756 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 22.256ms 01-13 13:45:41.457 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 10.842ms 01-13 13:45:42.026 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 21.661ms 01-13 13:45:42.306 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 26452(1138KB) AllocSpace objects, 0(0B) LOS objects, 38% free, 2MB/3MB, paused 3.173ms total 350.458ms 01-13 13:45:42.340 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 32.739ms 01-13 13:45:42.478 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 45.701ms 01-13 13:45:42.941 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 7.528ms 01-13 13:45:43.441 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 9.983ms 01-13 13:45:43.967 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 15.002ms 01-13 13:45:44.441 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 5.679ms 01-13 13:45:45.017 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 78.054ms 01-13 13:45:45.227 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 30991(1278KB) AllocSpace objects, 0(0B) LOS objects, 33% free, 2MB/3MB, paused 4.014ms total 530.324ms 01-13 13:45:45.248 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 20.060ms 01-13 13:45:46.952 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 6.040ms 01-13 13:45:47.519 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 24262(1051KB) AllocSpace objects, 0(0B) LOS objects, 33% free, 2MB/3MB, paused 28.907ms total 413.226ms 01-13 13:45:47.522 1353-1364/com.example.sharafievp.myfilm I/art: WaitForGcToComplete blocked for 276.630ms for cause HeapTrim 01-13 13:45:47.621 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 93.925ms 01-13 13:45:47.952 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 6.986ms 01-13 13:45:48.445 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 5.285ms 01-13 13:45:49.451 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 7.622ms 01-13 13:45:49.977 1353-1360/com.example.sharafievp.myfilm W/art: Suspending all threads took: 33.428ms 01-13 13:45:50.156 1353-1365/com.example.sharafievp.myfilm W/art: Suspending all threads took: 5.254ms 01-13 13:45:50.407 1353-1365/com.example.sharafievp.myfilm I/art: Background sticky concurrent mark sweep GC freed 27212(1124KB) AllocSpace objects, 0(0B) LOS objects, 31% free, 2MB/3MB, paused 11.058ms total 474.047ms
на english форумах пишут что проблема связана не с кодом, а с Android 5.0. Пользуюсь библиотекой Gson


Ответ

В общем ни одна из библиотек обработки JSON у меня не работает на Android 5.0. Написал собственный класс для обработки, используя стандартную библиотеку org.json. Теперь приложение не зависает.

вторник, 5 февраля 2019 г.

Потоки и IntentService

В каком потоке происходит работа IntentService? Вроде как по определению это подкласс обычного Service, у которого метод onHandleIntent отрабатывает в background потоке:
Clients send requests through Context.startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
...
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Но правильно ли я понимаю, что всё равно сам IntentService работает в главном (UI) потоке, и из него уже запускает новый worker/background-поток? И при завершении приложения IntentService будет убит вместе со всем приложением, до конца выполнится только текущий метод onHandleIntent, но следующий уже не будет запущен?
К примеру, если в активити есть следующий код:
for (int i = 0; i < 5; i++) { Intent intent = new Intent(this, MyIntentService.class); this.startService(intent); }
и приложение завершается, когда весь цикл выполнен, но метод onHandleIntent отработал только один раз, то больше метод onHandleIntent вызван не будет?
UPD
Например, если говорить об исходном коде класса IntentService
public abstract class IntentService extends Service { ... @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } ... @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } ... @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); }
Правильно ли я понимаю, что в этом случае (в примере с циклом) метод onStartCommand выполнится 5 раз, и вызовет 5 раз метод onStart, который с помощью mServiceHandler помещает intent-ы в очередь, но при завершении main-потока умирает вместе с ним?..


Ответ

В каком потоке происходит работа IntentService?
работа IntentService происходит в отдельном Thread, который создается во время создания сервиса, все остальные Message будут поститься на Looper от этого треда, те получается что это SingleQueue.
Но правильно ли я понимаю, что всё равно сам IntentService работает в главном (UI)?
Не совсем точно. По умолчанию все компоненты одного приложения работают в одном процессе, но вам никто не помешает запустить сервис из другого потока, внутри себя он создаст поток из контекста который вы передадите. Как только процесс завершится поток сервиса умрет.
И при завершении приложения IntentService будет убит вместе со всем приложением, до конца выполнится только текущий метод onHandleIntent, но следующий уже не будет запущен?
Да. Но подмечу если компоненты одного приложения работают в одном процессе.
и приложение завершается, когда весь цикл выполнен, но метод onHandleIntent отработал только один раз, то больше метод onHandleIntent вызван не будет?
не факт, здесь работа разных потоков может успеть вызываться, а может нет. Смотря как быстро вы убиваете процесс. Смею предположить если сделать, что-то типо System.exit(0) то не успеет даже 1-раз вызваться.
Правильно ли я понимаю, что в этом случае (в примере с циклом) метод onStartCommand выполнится 5 раз, и вызовет 5 раз метод onStart, который с помощью mServiceHandler помещает intent-ы в очередь, но при завершении main-потока умирает вместе с ним?.
Да.

среда, 10 октября 2018 г.

Android Thread.name

Я работаю с потоками в своем проекте. Среди прочих потоков, в двух разных классах создается две HandlerThread таким вот образом:
HandlerThread thread = new HandlerThread("ServiceThread", Process.THREAD_PRIORITY_DEFAULT);
Дальше они стартуются: thread.start();, и я использую их луперы. И только что я обнаружил, что они создаются с абсолютно одинаковыми именами (первый параметр в конструкторе - имя). Мой вопрос состоит в том, могут ли быть проблемы из за того, что у потоков одинаковые имена? Являются ли имена какими-то идентификаторами для потоков?


Ответ

Не будет проблем.
При создании нового HandlerThread вызывается конструктор:
public HandlerThread(String name, int priority) { super(name); mPriority = priority; }
Идем вглубь и видим
if (threadName == null) { this.name = "Thread-" + id; } else { this.name = threadName }
Что и есть практическим подтверждением написанного в Javadoc
Каждый поток имеет имя в целях идентификации. Более чем один поток может иметь такое же имя . Если имя не указано , когда создается поток, новое имя генерируется для него.