¿AsyncTask sigue esperando?
Un botón en una de mis actividades llama a AsyncTask que actualiza el cursor subyacente para SimpleCursorAdapter de un ListView. Cada vez que hago clic en el botón, se agrega un nuevo hilo para el AsyncTask y la tarea se completa (pasa al estado 'wait'). Si hago clic en el botón 5 o más veces, 5 AsyncTasks termina allí sentado con el estado de 'espera'. ¿Es esto normal o tengo una pérdida de memoria en alguna parte?
La AsyncTask
- Protocolos SSL / TLS y suites de cifrado con AndroidHttpClient
- GetView () no puede lanzar Exception
- ¿Cuál es la diferencia entre View.postDelayed () y Handler.postDelayed () en el hilo principal?
- Error al iniciar la primera aplicación de prueba: Android Packaging Problem?
- ¿Hay un equivalente de MethodHandle en Android?
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()); } }
Y el código en mi onCreate que llama a la tarea (cuando se carga la actividad por primera vez):
upAdapter = new updateAdapter().execute();
Y en el botón onClickListener:
// Reset wod_id _wod_id = -1; // Update the underlying SimpleCursorAdapter upAdapter = new updateAdapter().execute();
Stacktrace de uno de los AsyncTask (es lo mismo para todos ellos):
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
- Android FFmpegMediaPlayer Error (0, 0) mientras se reproduce?
- Http Post Con El Cuerpo
- NullPointerException en ActionBar.setHomeButtonEnabled
- Android Emulator "no responde ¿Desea cerrarlo?
- Cambiar la conectividad de Android con Robolectric
- Incorporación del protocolo XMPP a una aplicación de Android
- Cómo reducir la base de datos sqlite?
- ¿Cómo establecer un hipervínculo en textview clicable? Android Java
AsyncTask
debajo de la campana utiliza un ThreadPoolExecutor
. Esos hilos podrían no desaparecer un poco porque sería un desperdicio seguir creando y derribando esos hilos con demasiada frecuencia. Después de un tiempo, si crea más AsyncTasks
, encontrará que dejará de crear nuevos hilos y volverá a usar los antiguos.
Actualizar para tratar algunos detalles:
Se podría pensar que si hay hilos libres en la agrupación, no crearía nuevos, pero esto no es exactamente cierto. La idea es que hay un cierto número de hilos que son útiles para tener alrededor de mantener el procesamiento de tareas asíncronas. Esto se conoce como el tamaño de la agrupación principal. En el caso de AsyncTask
de Android, parecen haberlo establecido en 5. Si miras la documentación de ThreadPoolExecutor
dice:
Cuando se envía una nueva tarea en el método ejecutar (Runnable) y se ejecutan menos de los subprocesos corePoolSize, se crea un nuevo subproceso para controlar la solicitud, incluso si otros subprocesos de trabajo están inactivos.
También hay un máximo apropiado llamado el tamaño máximo de la piscina.
Lo que @kabuko dice es cierto, pero también creo que es una buena práctica cancelar la tarea antes de comenzar una nueva. Usted podría tener algunos comportamientos extraños en caso de que una de las viejas tareas continúen. Más sobre, en su caso no desea consultar su db más de una vez, sería inútil. Usted podría envolver la llamada a la tarea asíncrona en un método como este:
AsyncDataLoading loaderTask = null; private void runTask(){ if (loaderTask!=null && loaderTask.getStatus().compareTo(Status.FINISHED)!=0) { loaderTask.cancel(true); } loaderTask = new AsyncDataLoading(); loaderTask.execute(); }
También es una buena práctica desactivar el botón y volver a habilitarlo cuando se realiza la tarea asíncrona.
De todos modos esta solución no podría ser un buen ajuste para su arquitectura, no sé bastante sobre su código. Espero que ayude de todos modos.
- Android: respuesta de la actividad del mercado
- ¿Es posible distribuir uniformemente los botones a través del ancho de un android RELATIVE LAYOUT