tiempo - servicios en segundo plano android studio
Ejecutar múltiples tareas asíncronas al mismo tiempo, ¿no es posible? (7)
AsyncTask utiliza un patrón de grupo de subprocesos para ejecutar el material desde doInBackground (). El problema es inicialmente (en las primeras versiones del sistema operativo Android) el tamaño de la agrupación era de 1, lo que significa que no hay cálculos paralelos para un montón de AsyncTasks. Pero luego lo arreglaron y ahora el tamaño es 5, por lo que como máximo se pueden ejecutar 5 AsyncTasks simultáneamente. Lamentablemente no recuerdo en qué versión exactamente cambiaron eso.
ACTUALIZAR:
Aquí está lo que dice la API actual (2012-01-27) sobre esto:
Cuando se introdujo por primera vez, las AsyncTasks se ejecutaron en serie en un solo hilo de fondo. Comenzando con DONUT, esto se cambió a un grupo de subprocesos permitiendo que múltiples tareas funcionen en paralelo. Después de HONEYCOMB, se planea cambiar esto de nuevo a un solo hilo para evitar errores comunes de aplicación causados por la ejecución paralela. Si realmente desea una ejecución paralela, puede usar la versión executeOnExecutor (Executor, Params ...) de este método con THREAD_POOL_EXECUTOR; sin embargo, vea el comentario allí para advertencias sobre su uso.
DONUT es Android 1.6, HONEYCOMB es Android 3.0.
ACTUALIZACIÓN: 2
Vea el comentario de kabuko
del Mar 7 at 1:27
.
Resulta que para las API donde se usa "un grupo de subprocesos que permiten que varias tareas funcionen en paralelo" (comenzando desde 1.6 y terminando en 3.0), el número de AsyncTasks que se ejecutan simultáneamente depende de cuántas tareas se hayan pasado para su ejecución, pero no han terminado su doInBackground()
todavía.
Esto es probado / confirmado por mí en 2.2. Supongamos que tiene una AsyncTask personalizada que solo duerme un segundo en doInBackground()
. AsyncTasks utiliza una cola de tamaño fijo internamente para almacenar tareas retrasadas. El tamaño de la cola es 10 por defecto. Si inicia 15 sus tareas personalizadas en una fila, los primeros 5 ingresarán a su doInBackground()
, pero el resto esperará en una cola para un subproceso de trabajo libre. Tan pronto como cualquiera de los primeros 5 finalice y, por lo tanto, libere un subproceso de trabajo, una tarea de la cola comenzará la ejecución. Así que en este caso como máximo 5 tareas se ejecutarán simultáneamente. Sin embargo, si inicia 16 sus tareas personalizadas en una fila, las 5 primeras ingresarán a su doInBackground()
, las 10 restantes entrarán en la cola, pero para la 16ª se creará una nueva doInBackground()
trabajo para que comience a ejecutarse de inmediato. Así que en este caso como máximo 6 tareas se ejecutarán simultáneamente.
Hay un límite de cuántas tareas se pueden ejecutar simultáneamente. Como AsyncTask
usa un ejecutor de grupo de subprocesos con un número máximo limitado de subprocesos de trabajo (128) y la cola de tareas retrasadas tiene un tamaño fijo 10, si intenta ejecutar más de 138 tareas personalizadas, la aplicación se bloqueará con java.util.concurrent.RejectedExecutionException
.
A partir de 3.0, la API permite utilizar el ejecutor de su grupo de subprocesos personalizado mediante el AsyncTask.executeOnExecutor(Executor exec, Params... params)
. Esto permite, por ejemplo, configurar el tamaño de la cola de tareas retrasadas si el valor predeterminado 10 no es lo que necesita.
Como menciona @Knossos, hay una opción para usar AsyncTaskCompat.executeParallel(task, params);
desde la biblioteca de soporte v.4 para ejecutar tareas en paralelo sin molestar con el nivel de API. Este método quedó en desuso en el nivel de API 26.0.0.
ACTUALIZACIÓN: 3
Aquí hay una aplicación de prueba simple para jugar con varias tareas, ejecución en serie frente a paralela: https://github.com/vitkhudenko/test_asynctask
ACTUALIZACIÓN: 4 (gracias @penkzhou por señalar esto)
A partir de Android 4.4, AsyncTask
comporta de manera diferente a lo que se describió en la sección ACTUALIZACIÓN: 2 . Hay una solución para evitar que AsyncTask
cree demasiados subprocesos.
Antes de Android 4.4 (API 19) AsyncTask
tenía los siguientes campos:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
En Android 4.4 (API 19) los campos anteriores se cambian a esto:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
Este cambio aumenta el tamaño de la cola a 128 elementos y reduce el número máximo de subprocesos al número de núcleos de CPU * 2 + 1. Las aplicaciones aún pueden enviar el mismo número de tareas.
Estoy intentando ejecutar dos AsyncTasks al mismo tiempo. (La plataforma es Android 1.5, HTC Hero). Sin embargo, solo se ejecuta el primero. Aquí hay un fragmento simple para describir mi problema:
public class AndroidJunk extends Activity {
class PrinterTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String ... x) {
while (true) {
System.out.println(x[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new PrinterTask().execute("bar bar bar");
new PrinterTask().execute("foo foo foo");
System.out.println("onCreate() is done.");
}
}
La salida que espero es:
onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo
Y así. Sin embargo, lo que obtengo es:
onCreate() is done.
bar bar bar
bar bar bar
bar bar bar
El segundo AsyncTask nunca se ejecuta. Si cambio el orden de las instrucciones de ejecución (), solo la tarea foo producirá resultados.
¿Me estoy perdiendo algo obvio aquí y / o haciendo algo estúpido? ¿No es posible ejecutar dos AsyncTasks al mismo tiempo?
Edición: Me di cuenta de que el teléfono en cuestión funciona con Android 1.5, actualicé el problema descrito. en consecuencia. No tengo este problema con un HTC Hero con Android 2.1. Hmmm ...
El ejemplo de los desarrolladores de Android de cargar mapas de bits de manera eficiente usa una asíncrota personalizada (copiada de jellybean), por lo que puede usar el executeOnExecutor en apis inferiores a <11
http://developer.android.com/training/displaying-bitmaps/index.html
Descarga el código y ve al paquete util.
Es posible La versión de mi dispositivo Android es 4.0.4 y android.os.Build.VERSION.SDK_INT es 15
Tengo 3 hilanderos
Spinner c_fruit=(Spinner) findViewById(R.id.fruits);
Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables);
Spinner c_beverage=(Spinner) findViewById(R.id.beverages);
Y también tengo una clase de Async-Tack.
Aquí está mi código de carga spinner
RequestSend reqs_fruit = new RequestSend(this);
reqs_fruit.where="Get_fruit_List";
reqs_fruit.title="Loading fruit";
reqs_fruit.execute();
RequestSend reqs_vegetable = new RequestSend(this);
reqs_vegetable.where="Get_vegetable_List";
reqs_vegetable.title="Loading vegetable";
reqs_vegetable.execute();
RequestSend reqs_beverage = new RequestSend(this);
reqs_beverage.where="Get_beverage_List";
reqs_beverage.title="Loading beverage";
reqs_beverage.execute();
Esto está funcionando perfectamente. Uno a uno mis hilanderos cargados. Yo no usé executeOnExecutor.
Aquí está mi clase de tarea asíncrona
public class RequestSend extends AsyncTask<String, String, String > {
private ProgressDialog dialog = null;
public Spinner spin;
public String where;
public String title;
Context con;
Activity activity;
String[] items;
public RequestSend(Context activityContext) {
con = activityContext;
dialog = new ProgressDialog(activityContext);
this.activity = activityContext;
}
@Override
protected void onPostExecute(String result) {
try {
ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spin.setAdapter(adapter);
} catch (NullPointerException e) {
Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (Exception e) {
Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
super.onPostExecute(result);
if (dialog != null)
dialog.dismiss();
}
protected void onPreExecute() {
super.onPreExecute();
dialog.setTitle(title);
dialog.setMessage("Wait...");
dialog.setCancelable(false);
dialog.show();
}
@Override
protected String doInBackground(String... Strings) {
try {
Send_Request();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void Send_Request() throws JSONException {
try {
String DataSendingTo = "http://www.example.com/AppRequest/" + where;
//HttpClient
HttpClient httpClient = new DefaultHttpClient();
//Post header
HttpPost httpPost = new HttpPost(DataSendingTo);
//Adding data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("authorized","001"));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// execute HTTP post request
HttpResponse response = httpClient.execute(httpPost);
BufferedReader reader;
try {
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line) ;
}
JSONTokener tokener = new JSONTokener(builder.toString());
JSONArray finalResult = new JSONArray(tokener);
items = new String[finalResult.length()];
// looping through All details and store in public String array
for(int i = 0; i < finalResult.length(); i++) {
JSONObject c = finalResult.getJSONObject(i);
items[i]=c.getString("data_name");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Esto permite la ejecución paralela en todas las versiones de Android con API 4+ (Android 1.6+):
@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
else
asyncTask.execute(params);
}
Este es un resumen de la excelente respuesta de Arhimed.
Asegúrese de usar el nivel de API 11 o superior como objetivo de compilación del proyecto. En Eclipse, eso es Project > Properties > Android > Project Build Target
. Esto no romperá la compatibilidad con versiones anteriores para disminuir los niveles de API. No se preocupe, recibirá errores de pelusa si accidentalmente utiliza funciones introducidas más tarde que minSdkVersion
. Si realmente desea utilizar las funciones introducidas más tarde que minSdkVersion
, puede suprimir esos errores usando anotaciones, pero en ese caso, debe cuidarse de la compatibilidad. Esto es exactamente lo que sucedió en el fragmento de código anterior.
Haciendo la sugerencia de @sulai más genérica:
@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
else
asyncTask.execute(params);
}
Solo para incluir la última actualización (ACTUALIZACIÓN 4) en la respuesta inmaculada de @Arhimed en el excelente resumen de @sulai:
void doTheTask(AsyncTask task) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above
// Parallel AsyncTasks are possible, with the thread-pool size dependent on device
// hardware
task.execute(params);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to
// Android 4.3
// Parallel AsyncTasks are not possible unless using executeOnExecutor
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else { // Below Android 3.0
// Parallel AsyncTasks are possible, with fixed thread-pool size
task.execute(params);
}
}
si desea ejecutar tareas en paralelo, debe llamar al método executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name")
después de la versión Android 3.0; pero este método no existe antes de Android 3.0 y después de 1.6 porque se ejecuta en paralelo por sí mismo. Por lo tanto, sugiero que personalice su propia clase de AsyncTask en su proyecto, para evitar la excepción de lanzamiento en diferentes versiones de Android.