J'essaie de mettre à jour mon application pour gérer les changements de configuration (en particulier le changement d'écran) manuellement.Android: questions sur la gestion manuelle des modifications de configuration pendant l'exécution du thread
J'ai quelques questions sur ce qui se passe lorsque des changements surviennent au cours d'une exécution Thread.
J'ai créé une classe abstraite que j'appelle ThreadTask et qui utilise Threads and Handlers dans le looper du thread principal pour envoyer des mises à jour au thread principal. C'est mon implémentation d'AsyncTask mais avec des threads, je préfère utiliser AsyncTask car j'ai plus de contrôle sur elle.
Il dispose également de deux méthodes pour enregistrer un observateur aux événements ci-dessus, il utilise cette interface:
public interface TaskObserver {
void pre_execute();
void on_progress(ProgressData progress);
void finished(Object result);
void cancelled(Object result);
}
Les membres abstraits que la sous-classe doit mettre en œuvre sont:
abstract Object do_in_background();
et du béton les membres sont:
synchronized void add_observer(TaskObserver observer){
_observers.add(observer);
}
synchronized void remove_observer(TaskObserver observer){
_observers.remove(observer);
}
synchronized void post_execute(Object result) {
int observers = _observers.size();
for (int idx = 0; idx < observers; idx++) {
_observers.get(idx).finished(result);
}
}
///plus all the other methods of the interface
Donc quand j'implémente une classe de béton ça irait mething comme ceci:
public class MyThreadTask extends ThreadTask{
@Override
Object do_in_background() {
progress.primary_max = 5;
for (int cur = 0 ; cur < 5 ; cur++) {
progress.primary = cur;
publish();
Thread.Sleep(3000);
}
}
}
et je mis à jour l'activité qui appelle cela comme ceci:
static final string TAG ="my_main_activity";
MyDataFragment _data; //this is a datafragment, a fragment with retaininstancestate , and a public `MyThreadTask task` variable
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (_data == null) {
_data = (MyDataFragment)getFragmentManager().findFragmentByTag(TAG + "_data");
if (_data == null) {
_data = new MyDataFragment();
getFragmentManager().beginTransaction().add(_data, TAG + "_data").commit();
}
}
if (_data.task != null) {
_data.task.register(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (_data.task != null) {
_data.task.remove(this);
}
}
ce fait en sorte que je l'ai toujours une référence au fil correct
Quand je veux commencer la tâche Je le fais comme si:
button.setOnClickListener((v) -> {
if (_data.task != null) return; //to make sure only one thread starts at a time
_data.task = new MyThreadTask();
_data.task.register(this);
_data.task.start(); //this is not thread's start, it is mine, it does other things too
})
et quand le thread finit il appelle void f inished (résultat d'objets) que je manipule comme ceci:
void finished(Object result) {
try {
//get result;
} finally {
_data.task.remove(this);
_data.task = null;
}
}
voici mes questions:
a) est en déclarant mes méthodes d'observation synchronized nécessaire? Je l'ai fait juste pour être sûr, mais quand l'activité est détruite puis recréée, est-ce que ça se passe sur le même fil? Y a-t-il une chance par exemple qu'une progression_update puisse se produire pendant qu'un observateur est supprimé pendant onDestroy?
b) que se passe-t-il si un thread se termine et appelle post_execute (ce qui est important) lors d'un changement de configuration? la mise à jour sera-t-elle perdue?
c) Si en effet la mise à jour est perdue parce qu'elle n'a actuellement aucun observateur, existe-t-il un moyen, dans mon implémentation ou un autre, de gérer ce qui précède?
Merci d'avance pour toute aide que vous pouvez fournir
Je suis d'hébergement dans un fragment conservé, MyDataFragment _data est un fragment conservé. Merci pour la méthode isChangingConfigurations, cela aidera probablement. Merci aussi pour les informations sur AsyncTask, je vais jeter un coup d'oeil au code d'AsyncTask et voir si je peux reproduire ce comportement dans mon code aussi. – Cruces
Eh bien, j'ai vérifié le code d'AsyncTask, et je ne vois rien de spécial. postexecute étant exécuté lors d'un changement de configuration. Il semble utiliser un gestionnaire simple pour poster les données d'arrivée à la tâche qui à son tour appelle sur le texte, peut-être qu'il me manque quelque chose? – Cruces
@Cruces Ce n'est pas dans le code de 'AsyncTask'. C'est une conséquence du fait que le framework affiche toutes les étapes du changement de configuration dans le thread principal en bloc. –