AsyncTask продолжает ждать?

Кнопка в одном из моих действий вызывает AsyncTask, который обновляет основной курсор для SimpleCursorAdapter ListView. Каждый раз, когда я нажимаю кнопку, добавляется новый поток для AsyncTask, и задача завершается (переходит в состояние «wait»). Если я нажимаю кнопку 5 или более раз, 5 AsyncTasks заканчивается, сидя там с статусом «wait». Это нормально или у меня где-то есть утечка памяти?

AsyncTask

private class updateAdapter extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { // Open database connection if(_db == null || !_db.isOpen()) _db = new DatabaseWrapper(ActivityShowWOD.this).getWritableDatabase(); Cursor WODcursor; // Check if a wod_id is set if(_wod_id == -1) { // Grab filters from preferences and at the same time build SQLselection string SharedPreferences prefs = getSharedPreferences("Preferences", 0); String[] filterNames = getResources().getStringArray(R.array.filters_values); boolean[] filterValues = new boolean[filterNames.length]; String SQLselection = ""; for (int i = 0; i < filterNames.length; i++) { filterValues[i] = prefs.getBoolean(filterNames[i], false); // Build SQL query if(filterValues[i] == true) { SQLselection += filterNames[i] + " = 1 OR " + filterNames[i] + " = 0"; } else { SQLselection += filterNames[i] + " = 0"; } // Add an "AND" if there are more filters if(i < filterNames.length - 1) SQLselection += " AND "; } // Get all WODs matching filter preferences WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME, DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, SQLselection, null, null, null, null); // Move the Cursor to a random position Random rand = new Random(); WODcursor.moveToPosition(rand.nextInt(WODcursor.getCount())); // Store wod_id _wod_id = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_ID)); } else { // Get the cursor from the wod_id WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME, DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, DatabaseConstants.WORKOUTS_ID + " = " + _wod_id, null, null, null, null); WODcursor.moveToFirst(); } // Store WOD information into class instance variables and close cursor _wod_cfid = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_CFID)); _wod_name = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NAME)); _wod_notes = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NOTES)); WODcursor.close(); // Return all exercises pertaining to this WOD _excCursor = _db.query(DatabaseConstants.TBL_EXERCISES, new String[] { DatabaseConstants.EXERCISES_ID, DatabaseConstants.EXERCISES_EXERCISE, DatabaseConstants.EXERCISES_REPS, DatabaseConstants.EXERCISES_NOTES }, DatabaseConstants.EXERCISES_WOD_ID + " = " + _wod_id, null, null, null, DatabaseConstants.EXERCISES_ID + " ASC"); return null; } @Override protected void onPostExecute(Void result) { _adapter.changeCursor(_excCursor); _adapter.notifyDataSetChanged(); _WODlist.setOnItemClickListener(new WODlistClickListener()); } } 

И код в моем onCreate, который вызывает задачу (когда активность сначала загружена):

 upAdapter = new updateAdapter().execute(); 

И в кнопке onClickListener:

  // Reset wod_id _wod_id = -1; // Update the underlying SimpleCursorAdapter upAdapter = new updateAdapter().execute(); 

Stacktrace одного из AsyncTask (для всех он одинаковый):

 Object.wait(long, int) line: not available [native method] Thread.parkFor(long) line: 1535 LangAccessImpl.parkFor(long) line: 48 Unsafe.park(boolean, long) line: 317 LockSupport.park() line: 131 AbstractQueuedSynchronizer$ConditionObject.await() line: 1996 LinkedBlockingQueue.take() line: 359 ThreadPoolExecutor.getTask() line: 1001 ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1061 ThreadPoolExecutor$Worker.run() line: 561 Thread.run() line: 1096 

AsyncTask под капотом использует ThreadPoolExecutor . Эти потоки, возможно, не исчезнут, потому что это будет пустой тратой, чтобы продолжать создавать и срывать эти потоки слишком часто. Через некоторое время, если вы создадите больше AsyncTasks вы обнаружите, что перестанут создавать новые потоки, и они будут повторно использовать старые.

Обновите для рассмотрения некоторых деталей:

Вы могли бы подумать, что если в пуле есть свободные потоки, это не создаст новых, но это не совсем так. Идея состоит в том, что существует определенное количество потоков, которые могут быть полезны для продолжения обработки асинхронных задач. Это называется размером основного пула. В случае с AsyncTask Android они, похоже, установили значение 5. Если вы посмотрите на документацию для ThreadPoolExecutor она говорит:

Когда новая задача отправляется в выполнении метода (Runnable) и выполняется меньше потоков corePoolSize, для обработки запроса создается новый поток, даже если другие рабочие потоки неактивны.

Существует также максимально подходящий максимальный размер пула.

То, что @kabuko говорит, правда, но я также думаю, что это хорошая практика, чтобы отменить задачу перед тем, как начать новую. У вас может быть какое-то странное поведение, если одна из старых задач будет продолжаться. Более того, в вашем случае вы не хотите запрашивать свой db более одного раза, это было бы бесполезно. Вы можете связать вызов задачи async следующим способом:

 AsyncDataLoading loaderTask = null; private void runTask(){ if (loaderTask!=null && loaderTask.getStatus().compareTo(Status.FINISHED)!=0) { loaderTask.cancel(true); } loaderTask = new AsyncDataLoading(); loaderTask.execute(); } 

Это также хорошая практика, чтобы отключить кнопку и снова включить ее, когда задача async выполнена.

В любом случае, это решение не может быть подходящим для вашей архитектуры, я недостаточно знаю о вашем коде. Надеюсь, это все равно поможет.

Intereting Posts
Чтение файла, зарегистрированного через slf4android? Android: Где хранятся файлы базы данных? Как я могу получить доступ к моему локальному REST api с моего устройства Android? Android.content.res.Resources $ NotFoundException: Не удается найти идентификатор ресурса # 0xffffffff TextView с фиксированной шириной с растянутым составом Обновление Progressbar в панели уведомлений с использованием AsyncTask в службе? Выравнивание вкладок PagerTabStrip влево Перезапустить службу для приложения на SD-карте при перезагрузке SD-карты Обнаружение при выполнении ValueAnimator Сжатие изображений, таких как Whatsapp и другие мессенджеры на Android Сделать кнопку Datepicker похожим на ту, которая находится в приложении календаря Google. Как шифровать данные и хранить их в Sqlite Android Остановить программный щелчок мышью в программном обеспечении Android AsyncTask загрузка изображения RecyclerView Как определить, завершилась ли задание таймера