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
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é).
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éé.
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.
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.
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 (...).
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
}
}
/**
* 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);
}