Я пытаюсь реализовать класс, который может управлять входящими Runnables и отменять любые Runnables, независимо от того, где они находятся в своем коде, гарантированно.
Например, в Android я бы хотел сделать следующее.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
manager.submit(new Runnable() {
@Override
public void run() {
someLongRunningTaskThatCallsTheUi();
}
});
}
@Override
public void onPause() {
manager.cancel(); // cancels all Runnables to avoid issues with calling the UI
}
Как я могу подойти к этой проблеме, если метод Future cancel() на самом деле не гарантирует отмены исполняемого кода, а shutdownNow() ExecutorService имеет ту же проблему?
Из того, что я вижу, мне нужно было бы добавить проверку на наличие Thread.currentThread().isInterrupted() перед каждым фрагментом кода пользовательского интерфейса, который я хочу вызвать и выйти из метода, чтобы каким-то образом избежать дальнейших вызовов.
Я был под таким впечатлением, когда столкнулся с проблемой. Тогда есть ли лучший способ прийти к этому? Я хочу запустить длительную операцию в фоновом режиме одним нажатием кнопки, но также разрешить пользователю отступить, если он хочет, отменив операцию.
Вы сами пишете эти Runnables или это плагины сторонних производителей для вашего приложения?
Я их пишу. Я просто не хочу помещать if (isInterrupted) return; в несколько мест исполняемого файла. Кажется, это довольно хрупкий способ писать код.
Есть ли причина, по которой AsyncTask не работает? Его отмена не остановит фоновую работу, которая не проверяет статус, но гарантирует, что в потоке пользовательского интерфейса больше не произойдет обратных вызовов. Для процессов с несколькими шагами выполнение одной задачи может запускать следующую.
Думаю, я понимаю вашу точку зрения. Я попытаюсь взглянуть на это под другим углом. Обычно я избегаю AsyncTasks, потому что у меня были проблемы с ними в прошлом (например, в далеком прошлом), поэтому, возможно, пришло время вернуться к ним. Спасибо за помощь!




Рассмотрите возможность использования AsyncTask. Отмена AsyncTask не гарантирует, что фоновая работа остановится, если задача не проверит свой собственный статус. Но отмена действительно гарантирует, что onProgressUpdate и onPostExecute не будут вызваны. Если onProgressUpdate не подходит для обновления пользовательского интерфейса между шагами, поместите каждый шаг в отдельную задачу.
Несколько советов для AsyncTask:
Они как минимум пару раз меняли пул потоков по умолчанию. Если вам нужен больший контроль над выполнением, начните свои задачи с executeOnExecutor.
Остерегайтесь ссылок на действия. Плохое предложение (популяризированное известной книгой IIRC) гласит, что нужно присвоить задаче WeakReference деятельности и проверить ее перед доступом к пользовательскому интерфейсу. Это неверно, потому что структура может содержать ссылку на действие после вызова onDestroy, и когда он очищает свою ссылку, WeakReference не станет нулевым, пока GC не заметит, что действие не является полностью доступным. Вы должны поддерживать коллекцию запущенных задач внутри своей операции и отменять их, когда действие приостановлено или уничтожено.
Чтобы задачи выполнялись при изменении конфигурации, разместите их в сохраненном фрагменте без заголовка.
Вы, мощь, сможете сделать это с помощью какой-либо прямой манипуляции с байтовым кодом или переплетения кода. Если оставить в стороне эти темные искусства, вы просите не о том, как работают нити.