web-dev-qa-db-fra.com

Android: Comment mettre à jour une interface utilisateur à partir d'AsyncTask si AsyncTask est dans une classe distincte?

Je déteste la classe intérieure.

J'ai une activité principale qui lance une AsyncTask de "courte durée".

AsyncTask est dans un fichier séparé, n'est pas une classe interne d'activité principale

J'ai besoin d'une tâche asynchrone pour mettre à jour une vue texte de l'activité principale.

Je sais que je peux mettre à jour un TextView à partir de onProgressUpdate, si AsyncTask est une classe interne

Mais comment partir d'une tâche asynchrone externe et indépendante?

MISE À JOUR: Cela ressemble à travailler:

En acitivty j'appelle la tâche

backgroundTask = new BackgroundTask(this);
backgroundTask.execute();

Dans le constructeur j'ai

public BackgroundTask(Activity myContext)
{
    debug = (TextView) myContext.findViewById(R.id.debugText);
}

où le débogage était un champ privé d'AsyncTask.

Donc onProgressUpdate je peux

debug.append(text);

Merci pour toutes vos suggestions

36
realtebo

EDIT J'ai édité la réponse pour utiliser WeakReference


AsyncTask est toujours une classe distincte de Activity, mais je suppose que vous voulez dire qu'elle se trouve dans un fichier différent de votre fichier de classe d'activité, vous ne pouvez donc pas bénéficier d'être la classe interne de l'activité. Passez simplement le contexte d'activité comme argument à votre tâche asynchrone (c'est-à-dire à son constructeur)

class MyAsyncTask extends AsyncTask<URL, Integer, Long> {

    WeakReference<Activity> mWeakActivity;

    public MyAsyncTask(Activity activity) {
       mWeakActivity = new WeakReference<Activity>(activity);
    }

 ...

et utilisez quand vous en avez besoin (n'oubliez pas de NE PAS utiliser pendant pendant doInBackground()) c'est-à-dire quand vous appelleriez normalement

int id = findViewById(...)

dans AsyncTask, vous appelez, par exemple.

Activity activity = mWeakActivity.get();
if (activity != null) {
   int id = activity.findViewById(...);
}

Notez que notre Activity peut disparaître pendant que doInBackground() est en cours (donc la référence retournée peut devenir null), mais en utilisant WeakReference nous ne le faisons pas empêcher GC de le collecter (et de fuir la mémoire) et comme l'activité a disparu, il est généralement inutile d'essayer même de le mettre à jour (toujours, selon votre logique, vous voudrez peut-être faire quelque chose comme changer l'état interne ou mettre à jour la base de données, mais toucher l'interface utilisateur doit être ignoré).

37
Marcin Orlowski

Utilisation de l'interface 1) Créez une interface

public interface OnDataSendToActivity {
    public void sendData(String str);
}

2) L'implémente dans votre activité

public class MainActivity extends Activity implements OnDataSendToActivity{

     @Override
     protected void onCreate(Bundle savedInstanceState) {
          new AsyncTest(this).execute(new String[]{"AnyData"}); // start your task
     }

     @Override
     public void sendData(String str) {
         // TODO Auto-generated method stub

     }

}

3) Créer un constructeur dans AsyncTask (activité Activity) {} Enregistrez votre interface dans le fichier AsyncTask et appelez la méthode d'interface comme ci-dessous.

public class AsyncTest extends AsyncTask<String, Integer, String> {

    OnDataSendToActivity dataSendToActivity;
    public AsyncTest(Activity activity){
        dataSendToActivity = (OnDataSendToActivity)activity;
    }

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

}

Ici, votre OnPostExecute appellera après toutes les tâches effectuées par AsyncTask et obtiendra "résultat" comme paramètre, retourné par doInBackground () {return "";}.

Alors que "dataSendToActivity.sendData (result);" il appellera la méthode redéfinie de l'activité "public void sendData (String str) {}".

Un cas Edge à retenir: assurez-vous de passer this, c'est-à-dire le contexte de votre activité actuelle à AsyncTask et de ne pas créer une autre instance de votre activité, sinon votre Activity sera détruit et un nouveau est créé.

21
Ams

Créez une fonction statique dans votre classe d'activité en y passant le contexte pour mettre à jour votre affichage de texte, puis appelez cette fonction dans votre classe AsynkTask pour la mettre à jour.

Dans la classe Activity: public static void updateTextView () {

// votre code ici}

Dans la classe AynckTask, appelez cette fonction.

4
pyus13

Passez simplement le contexte (activité ou autre) à votre AsyncTask dans un constructeur puis dans onSuccess ou onProgressUpdate appelez tout ce dont vous avez besoin dans le contexte.

3
Manfred Moser

J'ai écrit une petite extension à AsyncTask pour ce genre de scénario. Il vous permet de conserver votre AsyncTask dans une classe distincte, mais vous donne également un accès pratique à l'achèvement des tâches:

public abstract class ListenableAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{

    @Override
    protected final void onPostExecute(Result result) {
        notifyListenerOnPostExecute(result);
    }

    private AsyncTaskListener<Result> mListener;
    public interface AsyncTaskListener<Result>{
        public void onPostExecute(Result result);
    }
    public void listenWith(AsyncTaskListener<Result> l){
        mListener = l;
    }
    private void notifyListenerOnPostExecute(Result result){
        if(mListener != null)
            mListener.onPostExecute(result);
    }

}

Donc, vous étendez d'abord ListenableAsyncTask au lieu d'AsyncTask. Ensuite, dans votre code d'interface utilisateur, créez une instance concrète et définissez listenWith (...).

3
newbyca

La question a déjà été répondue, je suis toujours en train de poster comment cela devrait être fait, je suppose ..

Classe d'activité principale

  public class MainActivity extends Activity implements OnClickListener
    {

        TextView Ctemp;

        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Ctemp = (TextView) findViewById(R.id.Ctemp);
            doConv = (Button) findViewById(R.id.doConv);
            doConv.setOnClickListener(this);
        }

        @Override
        public void onClick(View arg0) // The conversion to do
        {
            new asyncConvert(this).execute();
        }
    }

maintenant dans la classe async

public class asyncConvert extends AsyncTask<Void, Void, String>
{
    SoapPrimitive response = null;
    Context context;

    public asyncConvert(Context callerclass)
    {
        contextGUI = callerclass;
    }
.
.
.
.
protected void onPostExecute(String result)
    {
        ((MainActivity) contextGUI).Ctemp.setText(result); // changing TextView
    }
}
2
Sujal Mandal
    /**
     * Background Async Task to Load all product by making HTTP Request
     * */
     public  static class updateTExtviewAsyncTask extends AsyncTask<String, String, String> {

        Context context;
        ProgressDialog pDialog;
        String id, name;

        String state_id;

        //--- Constructor for getting network id from asking method

        public  updateTExtviewAsyncTask(Context context,String id,String city) 
        {
            context   = context;
            state_id  = id;
            city_name = city;
        }       
        /* *
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() 
        {
            super.onPreExecute();
            pDialog = ProgressDialog.show(context, "","Please wait...", true, true);
            pDialog.show();

        }

        /**
         * getting All products from url
         * */
        protected String doInBackground(String... args) 
        {
            return null;
        }

        /**
         * After completing background task Dismiss the progress dialog
         * **/
            protected void onPostExecute(String file_url)  {

                     YourClass.UpdateTextViewData("Textview data");
        }
    }

// place ce code dans votre classe d'activité et déclare également la mise à jour de textview statique

    public static void  UpdateTextViewData(String tvData) 
{
   tv.setText(tvData);
}
1
Lucky Rana