web-dev-qa-db-fra.com

android asynctask envoyant des rappels à l'interface utilisateur

J'ai la classe asynctask suivante qui ne fait pas partie de l'activité. Dans l'activité, je suis en train d'initialiser le masque asynchrone et je souhaite que celui-ci signale les rappels à mon activité. C'est possible? Ou le asynctask doit-il être dans le même fichier de classe que l'activité?

protected void onProgressUpdate(Integer... values) 
{
    super.onProgressUpdate(values);
    caller.sometextfield.setText("bla");
}

Quelque chose comme ça?

144
Asaf Nevo

Vous pouvez créer un interface, le transmettre à AsyncTask (dans le constructeur), puis appeler une méthode dans onPostExecute().

Par exemple:

Votre interface:

public interface OnTaskCompleted{
    void onTaskCompleted();
}

Votre activité:

public class YourActivity implements OnTaskCompleted{
    // your Activity
}

Et votre AsyncTask:

public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object to required type
    private OnTaskCompleted listener;

    public YourTask(OnTaskCompleted listener){
        this.listener=listener;
    }

    // required methods

    protected void onPostExecute(Object o){
        // your stuff
        listener.onTaskCompleted();
    }
}

EDIT

Depuis que cette réponse est devenue très populaire, je veux ajouter certaines choses.

Si vous débutez dans le développement de Android, AsyncTask est un moyen rapide de faire fonctionner les choses sans bloquer le fil de l'interface utilisateur. Cela résout effectivement certains problèmes, il n’ya rien de mal à la façon dont la classe fonctionne elle-même. Cependant, cela entraîne certaines implications, telles que:

  • Possibilité de fuite de mémoire. Si vous continuez à faire référence à votre Activity, il restera en mémoire même après que l'utilisateur a quitté l'écran (ou fait pivoter l'appareil).
  • AsyncTask ne fournit pas le résultat à Activity si Activity était déjà détruit. Vous devez ajouter du code supplémentaire pour gérer tout cela ou effectuer deux fois des opérations.
  • Code contourné qui fait tout dans Activity

Lorsque vous sentez que vous avez suffisamment mûri pour passer à Android, jetez un œil à cet article , qui, à mon avis, est un meilleur moyen de développer vos applications Android avec asynchrone. opérations.

390
Dmitry Zaytsev

J'ai senti que l'approche ci-dessous est très facile.

J'ai déclaré une interface pour le rappel

public interface AsyncResponse {
    void processFinish(Object output);
}

Ensuite, créé une tâche asynchrone pour répondre à tous les types de demandes parallèles

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

    //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

Ensuite, a appelé la tâche asynchrone lors du clic sur un bouton dans l'activité Classe.

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {

        Button mbtnPress = (Button) findViewById(R.id.btnPress);

        mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);          
                        mbtnPress.setText((String) output);
                    }
                });
                asyncTask.execute(new Object[] { "Youe request to aynchronous task class is giving here.." });

            }
        });
    }
}

Merci

44
Arshad

En complétant les réponses ci-dessus, vous pouvez également personnaliser vos options de repli pour chaque appel asynchrone que vous effectuez, de sorte que chaque appel à la méthode ASYNC générique remplisse des données différentes, en fonction du contenu onTaskDone que vous y avez mis.

  Main.FragmentCallback FC= new  Main.FragmentCallback(){
            @Override
            public void onTaskDone(String results) {

                localText.setText(results); //example TextView
            }
        };

new API_CALL(this.getApplicationContext(), "GET",FC).execute("&Books=" + Main.Books + "&args=" + profile_id);

Rappelez: j'ai utilisé l'interface sur l'activité principale où "Main" vient, comme ceci:

public interface FragmentCallback {
    public void onTaskDone(String results);


}

Mon post API se présente comme suit:

  @Override
    protected void onPostExecute(String results) {

        Log.i("TASK Result", results);
        mFragmentCallback.onTaskDone(results);

    }

Le constructeur de l'API ressemble à ceci:

 class  API_CALL extends AsyncTask<String,Void,String>  {

    private Main.FragmentCallback mFragmentCallback;
    private Context act;
    private String method;


    public API_CALL(Context ctx, String api_method,Main.FragmentCallback fragmentCallback) {
        act=ctx;
        method=api_method;
        mFragmentCallback = fragmentCallback;


    }
6
Miguel

Je vais répéter ce que les autres ont dit, mais je vais simplement essayer de simplifier les choses ...

D'abord, créez simplement la classe Interface

public interface PostTaskListener<K> {
    // K is the type of the result object of the async task 
    void onPostTask(K result);
}

Deuxièmement, créez la AsyncTask (qui peut être une classe statique interne de votre activité ou de votre fragment) qui utilise l'interface, en incluant une classe concrète. Dans l'exemple, PostTaskListener est paramétré avec String, ce qui signifie qu'il attend une classe String à la suite de la tâche asynchrone.

public static class LoadData extends AsyncTask<Void, Void, String> {

    private PostTaskListener<String> postTaskListener;

    protected LoadData(PostTaskListener<String> postTaskListener){
        this.postTaskListener = postTaskListener;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        if (result != null && postTaskListener != null)
            postTaskListener.onPostTask(result);
    }
}

Enfin, la partie où vous combinez votre logique. Dans votre activité/fragment, créez le PostTaskListener et transmettez-le à la tâche asynchrone. Voici un exemple:

...
PostTaskListener<String> postTaskListener = new PostTaskListener<String>() {
    @Override
    public void onPostTask(String result) {
        //Your post execution task code
    }
}

// Create the async task and pass it the post task listener.
new LoadData(postTaskListener);

Terminé!

2
ichalos