Выполняются ли обратные вызовы в основном потоке (UI)?
Существует много API Android SDK, в которых зарегистрированы обработчики обратного вызова. Для конкретного примера, с помощью MediaPlayer вы можете установить обратный вызов onCompletionListener. Будут вызваны эти обратные вызовы из основного (UI) потока? Если ответ "зависит", тогда я ищу некоторые общие правила для того, какие вызовы будут вызываться из основного потока по сравнению с другим потоком. Документация SDK, похоже, не говорит об этом. (Возможно, я пропустил это.)
Кажется важным знать, потому что, если мне гарантированы обратные вызовы с основным потоком, я могу пропустить некоторую синхронизацию потоков данных, разделяемых между разными местами кода. Если я вынужден быть пессимистичным из-за незнания, тогда я должен написать дополнительный код блока синхронизации и беспокоиться о взаимоблокировках, целостности данных и снижении производительности.
Ответы
Ответ 1
Один случай, когда Android будет вызывать ваш код в каком-то другом потоке, будет, если вы создадите удаленную службу, открытую через AIDL - эти методы AIDL будут вызваны в потоке связующего, а не в главном потоке приложения.
Однако это исключение. Как отмечали другие, подавляющее большинство из них вызвано основной темой приложения.
Ответ 2
В случае сомнений вы можете использовать Log.i("TAG", Thread.currentThread().getName());
и посмотреть:)
Ответ 3
По моему опыту, эти обратные вызовы всегда возвращаются к потоку, отличному от UI. Вы пробовали Activity.runOnUiThread()
, чтобы убедиться, что ваш код работает в потоке пользовательского интерфейса? Вы по-прежнему будете использовать производительность, потому что для запуска этого кода требуется больше времени, но вы бы избежали некоторых из наиболее распространенных проблем с синхронизацией потоков.
Ответ 4
В общем случае обратные вызовы будут возникать в потоке, в котором выполняется событие. Если вы зарегистрируете обратный вызов и начнете что-то играть в потоке, отличном от UI, тогда обратный вызов будет выполняться в потоке, отличном от UI. Однако Android не будет создавать новые потоки в фоновом режиме самостоятельно.
Все события, связанные с UI, должны встречаться в потоке пользовательского интерфейса, поэтому вы можете gauarentee, что обратные вызовы обработчика кликов и т.д. будут возникать в потоке пользовательского интерфейса.
Как указал Aaron C, вы можете использовать Activity.runOnUiThread, чтобы заставить там происходить.
Кроме того, AsyncTask может быть очень полезен для выполнения быстрой фоновой работы, где вам нужно выполнить какой-либо этап завершения, который должен быть включен поток uI.
edit: Пример из комментариев.
public void MyWorker {
private OnCompleteListener onCompleteListener;
public void setOnCompleteListener(OnCompleteListener onCompleteListener) {
this.onCompleteListener = onCompleteListener;
}
public void doWork() {
// do lots of work here
onCompleteListener.onComplete();
}
}
// somewhere in my Activity
public void onCreate() {
final MyWorker worker = new MyWorker();
worker.setOnCompleteListener(new OnCompleteListener() { ... });
new Thread(new Runnable() {
public void run() {
worker.doWork();
}
}).start();
}
В этом примере функция callback onComplete будет запущена из потока, отличного от UI. Поток будет завершен после завершения завершения.
Ответ 5
Еще одно исключение: когда вы используете WebView. Когда javascript вызывает функцию Java, такой вызов не будет выполняться в основном потоке
Ответ 6
Что-то подобное возникло, когда я работал над API-интерфейсом. Как мы знаем, мы предоставляем обратный вызов для служб местоположения, чтобы мы получили уведомление, как только мы приобрели место.
Поэтому я делал что-то в этом обратном вызове, который занимал много времени, как использование API-интерфейсов Geocoder.
Я был под впечатлением до этого, этот обратный вызов вызывается из другого потока и, следовательно, не будет выполняться в основном потоке пользовательского интерфейса. Но я вижу, что это не так.
Итак, какой код, который я пишу в этом слушателе, будет выполнен в основном потоке.
Теперь то, что я не понимаю, как они это делают, заключается в использовании standerd-функции runOnUIThread()
???
Ответ 7
У меня была эта проблема с Задачами на днях. Вы можете проверить эту ссылку
Прослушиватели, подключенные к потоку, по умолчанию запускаются в главном потоке приложения. При подключении слушателя вы также можете указать исполнителя, который используется для планирования слушателей.
// Create a new ThreadPoolExecutor with 2 threads for each processor on the
// device and a 60 second keep-alive time.
int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(numCores * 2, numCores *2,
60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
task.addOnCompleteListener(executor, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
// ...
}
});