una - peticiones asincronas android
Android llamando a AsyncTask justo después de otro finalizado (7)
Desde el código que mostró no parece tener sentido generar una segunda tarea. Simplemente obtenga su imagen dentro de doInBackground
de la primera tarea inmediatamente después de la autorización. Si necesita actualizar la interfaz de usuario intermedia, puede hacerlo en el proceso de actualización.
Tengo algún problema con Android AsyncTask. Hay una actividad que contiene un texto, un botón y una imagen. Cuando un usuario ingresa a esta actividad, comienzo una asíncrona para verificar si el usuario puede avanzar desde la actividad (hasta que la tarea no finalice el botón no está activo). Entonces quiero comenzar otra asintala para obtener la imagen. Así que hice una clase interna:
AsyncTask<String, Void, JSONObject>() authTask = new AsyncTask<String, Void, JSONObject>() {
@Override
protected JSONObject doInBackground(String... params) {
//call the rest api
}
@Override
protected void onPostExecute(JSONObject result) {
// check the result
// and make another asynctask
AsyncTask<String, Void, Bitmap> imageTask = new Async.... {
// get image
}
imageTask.execute();
}
}
y llamo a authTask.execute();
desde el hilo de la interfaz de usuario.
Tengo un mal presentimiento sobre esto, especialmente parece que no funciona (está bien algunas veces, pero de repente se "congela": no hay excepción, solo se cuelga y la barra de progreso está girando. No sucede nada y el botón no estará activo). ¿Hay otra forma de obtener una información y, cuando haya terminado, comience de inmediato otra tarea?
UDPATE: Estoy trabajando con el nivel 10 de api. En authTask obtengo la información necesaria para iniciar imageTask (algún id), así que tengo que llamar a estas tareas en una fila. En api nivel 10 es posible?
¡Gracias por adelantado!
Br, peter
He resuelto este tipo de problema cuando tuve que descargar algo de una base de datos antes de iniciar sesión en el usuario en la aplicación, con esto solucioné este problema.
Para usar ObservableInteger
puedes hacer esto
primero declararlo
private ObservableInteger mObsInt;
luego, en su onCreate, tendrá un oyente esperando a que cambien los valores de mObsInt; después de que esos valores cambien, puede hacer lo que quiera
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
@Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
//Do something if the first asyncTask finishes
if (mObsInt.get()==2){
//Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
Entonces, ¿cómo funciona?
ObservableInteger
buscará cambios en la variable mObsInt
, así que digamos que si mObsInt
es igual a 1 hará algo, si es igual a 2 hará otra cosa, así que, para resolver este problema con 2 asynctasks
es fácil, cuando uno de los asynctasks
finalizan mObsInt
será igual a 1, si el otro asyncTask
finaliza, mObsInt
será mObsInt++
, y luego su mObsInt
será igual a 2, el oyente esperará los valores, y luego hará lo que quiera hacer cuando los valores coinciden con su declaración en el método onCreate
ahora, solo en sus asynctasks simplemente ponga en su método onPostExecute () esta línea
mObsInt.set(mObsInt.get()+1);
así que si el primer final asíncrono, mObsint == 1, si el segundo finaliza mObsInt == 2, y luego manejas lo que quieres hacer en tu método onCreate
Espero que esto te ayude, me haya ayudado.
Puede obtener más información en este documento: https://developer.android.com/reference/android/databinding/ObservableInt.html
feliz codificación!
No es un buen diseño para anidar AsyncTask. Haga todo el trabajo pesado en doInBackground y simplemente publique / actualice los resultados. En otras palabras, combine el procesamiento de la segunda AsyncTask en su primera.
Tengo una idea para hacer series asíncronas en una sola tarea asíncrona :
protected Boolean doInBackground(String... params) {
if(params[0] == "taskA") {
//do somthing
params[0] = "taskB";
}
if(params[0] == "taskB") {
//do somthing
params[0] = "taskC";
}
if(params[0] == "taskC") {
//do somthing
params[0] = "taskD";
}
if(params[0] == "taskD") {
//do somthing
return true;
}
Y en tu hilo principal simplemente llama a una tarea asíncrona como esta:
ShowMyProgress(); //if you like
new MyAsyncTask().execute("taskA");
Y, finalmente, puede ocultar su progreso en onPostExecute como:
protected void onPostExecute(final Boolean success) {
if (success) {
....
HideMyProgress();
}
}
puede usar getStatus()
verificar si la AsyncTask
está pendiente, en ejecución o finalizada, y cuándo puede comenzar su nueva tarea.
if(authTask .getStatus() == AsyncTask.Status.PENDING){
// My AsyncTask has not started yet
}
if(authTask .getStatus() == AsyncTask.Status.RUNNING){
// My AsyncTask is currently doing work in doInBackground()
}
if(authTask .getStatus() == AsyncTask.Status.FINISHED){
// START NEW TASK HERE
}
Ejemplo para su aplicación:
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
if (authTask != null && authTask.getStatus() == AsyncTask.Status.FINISHED) {
//START YOUR NEW TASK HERE
}
else
{
//IGNORE BUTTON CLICK
}
}
});
1:
Podría escribir el código para authTask y luego para imageTask, uno después del otro, dentro de un solo doInBackground()
. Esta única instancia de AsyncTask se activaría mediante una sola instrucción execute()
. Esto puede o no ser práctico dependiendo de las interacciones de interfaz de usuario necesarias.
2:
Edición: como señala kabuku, esta información es principalmente para HoneyComb +. Antes de HoneyComb definitivamente iría con la opción 1 arriba. executeOnExecutor() es api nivel 11+
En las versiones de Receent, execute()
enviará sus AsyncTasks en serie de forma predeterminada (ICS +). Si desea asegurarse de que esto suceda, especifique el ejecutor serie.
En tu caso esto sería:
authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// Image task will only be done AFTER textViewTask is done
imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
Y para las nuevas versiones un sencillo.
...
// ICS+ and pre honeycomb (I think)
authTask.execute();
// Image task will only be done AFTER textViewTask is done
imageTask.execute();
...
De la documentación de AsycnTask.execute ():
Nota: esta función programa la tarea en una cola para un solo hilo de fondo o grupo de hilos en función de la versión de la plataforma. 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.
PD: para ejecutar tareas independientes entre sí, debe usar AsyncTask.THREAD_POOL_EXECUTOR
. Eso requiere un ejecutor diferente:
// Go parallel! (NOT what you want)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
int count;
private void attemptConnect()
{
count = 0;
str_lang = "English";
str_wait = "Plaese Wait";
new AllQuestion().execute();
}
private class AllQuestion extends AsyncTask<String, String, String> {
ProgressDialog pg;
@Override
protected void onPreExecute() {
super.onPreExecute();
pg = new ProgressDialog(LanguageActivity.this);
pg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pg.setMessage(str_wait);
pg.setCancelable(false);
pg.show();
}
@Override
protected String doInBackground(String... strings) {
try {
SoapObject soapObject = new SoapObject(AppConstant.NAMESPACE, AppConstant.QUESTION_SOAP_METHOD);
soapObject.addProperty("language", str_lang);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE se = new HttpTransportSE(AppConstant.webUrl);
se.call(AppConstant.QUESTION_SOAP_ACTION, envelope);
Object responce = envelope.getResponse();
Log.d("Question List:=>>", "" + responce);
return responce.toString();
} catch (Exception e) {
e.printStackTrace();
pg.dismiss();
return null;
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (pg.isShowing()) {
pg.dismiss();
Log.i(TAG, s);
if (s != null || !s.equalsIgnoreCase("")) {
try {
JSONArray array = new JSONArray(s);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
String queId = obj.getString(TAG_QID);
String que = obj.getString(TAG_QUE);
String str_Opt = obj.getString(TAG_OPT);
question = new Question(queId, que, str_lang, str_catId, str_Opt, manager.getDateTime());
helper.insertQuestion(question);
}
count++;
if (count < 5) {
if (count == 1) {
str_lang = "German";
str_wait = "bitte warte einen Moment";
new AllQuestion().execute();
}
if (count == 2) {
str_lang = "Italian";
str_wait = "per favore aspetta un momento";
new AllQuestion().execute();
}
if (count == 3) {
str_lang = "Chinese";
str_wait = "请稍候";
new AllQuestion().execute();
}
if (count == 4) {
str_lang = "French";
str_wait = "patientez s''il-vous-plait";
new AllQuestion().execute();
}
Log.d("All Question:-", question.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}