IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

ProgressDialog - AsyncTask + Changement d'orientation


Sujet :

Android

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut ProgressDialog - AsyncTask + Changement d'orientation
    Bonjour,

    J'ai un gros soucis avec la gestion de l'orientation et l'affichage d'une ProgressDialog pendant un long traitement.
    En effet si je pivote l'orientation pendant que la progress dialog est active, ça me faut planter mon programme...

    Voici mon implementation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    // android:configChanges="keyboardHidden|orientation" dans le manifest
    public class ProgTv extends Activity {
     
    	private LoadProgTvData progData;
    	/** Called when the activity is first created. */
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
     
    		//loadProgTvData();
    	}
     
    	@Override
    	public void onConfigurationChanged(Configuration newConfig) {
    		super.onConfigurationChanged(newConfig);
    		setContentView(R.layout.main);
    	}
     
    	@Override
    	public Object onRetainNonConfigurationInstance() {
    		progData.setActivity(null);
    		return progData;
    	}
     
    	@Override
    	protected void onResume() {
    		super.onResume();
    		loadProgTvData();
    	}
     
    	private void loadProgTvData() {
    		final Object retained = getLastNonConfigurationInstance();
    		if(retained instanceof LoadProgTvData) {
    			progData = (LoadProgTvData) retained;
    			progData.setActivity(this);
    		} else {
    			progData = new LoadProgTvData(this, null);
    		}
    	}
    }
    LoadProgTvData :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    public class LoadProgTvData {
    	private Activity activity;
    	private static List<ProgTvObj> lst_prog = new ArrayList<ProgTvObj>();
    	private static ProgTvAdapter progTvAdapter = null;
            private Hours progHours;
    	public static enum Hours { BEGINING_EVENING, END_EVENING };
     
    	public LoadProgTvData(Activity activity, Hours h) {
    		this.activity = activity;
                    this.progHours = h;
     
    		if(lst_prog.isEmpty())
    			new ListRefresher().execute();
    		else
    			refreshListView();
    	}
     
    	public void setActivity(Activity activity) {
    		this.activity = activity;
    		if(!lst_prog.isEmpty())
    			refreshListView();
    	}
     
    	/**
             * Set List of ProgTvObj from an XML stream
             */
    	private void setListFromXml() {
    		// SAX Parser
    		try {
    			ProgSaxXml px = new ProgSaxXml(activity.getAssets().open("soir.xml")); // SAX Parser		
    			lst_prog = px.getProgList();
    		} catch (MalformedURLException e) {
    			Log.d("MalformedURLException", "XML Url is malformed", e);
    			throw new RuntimeException(e);
    		} catch (IOException e) {
    			Log.d("IOException", e.toString());
    		}
    	}
     
    	/**
             * Set Adapter of ListView to fill it with ProgTvObj 
             */
    	public void refreshListView() {
    		//Hours progHours = (Hours) getIntent().getSerializableExtra("tabHours"); // Get Hours value or null if not defined
    		if(null != activity) {
    			if(null == progTvAdapter)			
    				progTvAdapter = new ProgTvAdapter(activity);
    			if(null != progHours)
    				progTvAdapter.setListProg(myUtils.filter(lst_prog, progHours));
    			else
    				progTvAdapter.setListProg(lst_prog);
    			ListView lstview_prog = (ListView)activity.findViewById(R.id.lstview_prog);
    			lstview_prog.setAdapter(progTvAdapter);
    			lstview_prog.setOnItemClickListener(progTvAdapter);
    		}
    	}
     
    	class ListRefresher extends AsyncTask<Uri, Void, Void> {
    		private ProgressDialog progressDialog;
    		@Override
    		protected void onPreExecute() {
    			if(!lst_prog.isEmpty()) {
    				this.cancel(true);
    				refreshListView();
    			} 
    			else
    				progressDialog = ProgressDialog.show(activity, null, "Chargement en cours...");
    		}
     
    		@Override
    		protected Void doInBackground(Uri... params) {
    			setListFromXml();
    			return null;
    		}
     
    		@Override
    		protected void onPostExecute(Void result) {
    			progressDialog.dismiss();
    			refreshListView();
    		}
    	}
    }
    Sachant que si je met loadProgTvData(); dans le OnResume c'est parce que mon Activity est un onglet de mon tableau et le faut de changer d'onglet ne rapelle pas OnCreate. Or j'ai besoin que ma liste soit rafraichit à chaque passage.

    Je pense que le problème viens du fait que la ProgressDialog est crée dans un context et le changement d'orientation change le context et donc au moment du dismiss il doit pas savoir quoi faire.

    Si vous pouviez m'aider ça serai vraiment sympa. Car le problème sur le lequel je bloque est quand même une chose que tout le monde doit réaliser dans une appli mobile (telechargement avec message d'attente...).

  2. #2
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Salut , pour la gestion de l'orientation tu n'as pas besoin de passer par
    onConfigurationChanged.

    Regarde plutôt du côté de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	protected Dialog onCreateDialog(int id) {
    http://developer.android.com/guide/t...i/dialogs.html

    Il gère tout seul le dialogue lors d'une rotation .

    Si tu as un souci avec cette procédure fais signe .

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    J'ai rajouté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    protected Dialog onCreateDialog(int id) {
    	if(id == 0){
    		ProgressDialog loadingDialog = new ProgressDialog(this);
    		loadingDialog.setMessage("Chargement en cours...");
    		loadingDialog.setIndeterminate(true);
    		loadingDialog.setCancelable(true);
    		return loadingDialog;
    	} 
    	return super.onCreateDialog(id);
    }
    et dans la inner class de LoadProgTvData j'ai modifié :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class ListRefresher extends AsyncTask<Uri, Void, Void> {
    	//private ProgressDialog progressDialog;
    	@Override
    	protected void onPreExecute() {
    		if(!lst_prog.isEmpty()) {
    			this.cancel(true);
    			refreshListView();
    		} else
    			activity.showDialog(0);
    		/*else
    			progressDialog = ProgressDialog.show(activity, null, "Chargement en cours...");*/
    	}
     
    	@Override
    	protected Void doInBackground(Uri... params) {
    		setListFromXml();
    		return null;
    	}
    	@Override
    	protected void onPostExecute(Void result) {
    		//progressDialog.dismiss();
    		activity.dismissDialog(0);
    		refreshListView();
    	}
    }

    Mais j'obtiens le message d'erreur suivant :

    ERROR/AndroidRuntime(5089): java.lang.NullPointerException
    ERROR/AndroidRuntime(5089): at org.prozero.util.LoadProgTvData$ListRefresher.onPostExecute(LoadProgTvData.java:191)
    ERROR/AndroidRuntime(5089): at org.prozero.util.LoadProgTvData$ListRefresher.onPostExecute(LoadProgTvData.java:1)
    ....


    La ligne 191 est la ligne avec activity.dismissDialog(0); -> toujours le problème du dismiss et crash de l'appli.
    Est ce que mon implementation est bonne ?

  4. #4
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Salut,

    Garde en mémoire ta progress pour pouvoir interagir directement dessus.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private ProgressDialog loadingDialog = null;
    protected Dialog onCreateDialog(int id) {
         super.onCreateDialog(id);
         if(id == 0){
    		loadingDialog = new ProgressDialog(this);
    		loadingDialog.setMessage("Chargement en cours...");
    		loadingDialog.setIndeterminate(true);
    		loadingDialog.setCancelable(true);
    		return loadingDialog;
    	} 
    	return null;
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	@Override
    	protected void onPreExecute() {
    		if(!lst_prog.isEmpty()) {
    			this.cancel(true);
    			refreshListView();
    		} else
    			showDialog(0);
     
    	}


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    	@Override
    	protected void onPostExecute(Void result) {
    		if(loadingDialog != null)
                        loadingDialog.dismiss();
     
    		refreshListView();
    	}

  5. #5
    Jay
    Jay est déconnecté
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2002
    Messages : 124
    Par défaut
    Bonjour,

    Sinon tu bloques la rotation de ton Activity.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <activity android:name="TonActivity"
    android:screenOrientation="portrait"></activity>
    Cordialement,

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Citation Envoyé par Feanorin Voir le message
    Salut,

    Garde en mémoire ta progress pour pouvoir interagir directement dessus.
    Malheureusement, la AsyncTask (qui fait le showDialog) est dans une classe à part et n'as donc pas accès aux membres de mon Activity (sauf via la valeur de activity passée en param à la classe).

    En revanche j'ai outre passé le problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    @Override
    protected void onPostExecute(Void result) {
    	//progressDialog.dismiss();
    	try {
    		activity.dismissDialog(0);
    	} catch(Exception e) {	}
    	refreshListView();
    }
    Le try catch permet de ne pas traiter la NullException (car sinon il la throw au RunTime).
    Plus de message, plus de plantage et en plus ça marche...mais c'est pas forcement la meilleure solution...

    @Jay : oui mais je voudrai pouvoir garder la rotation...


    Ou alors il faudrait que ma classe à part (LoadProgTvData) hérite de Activity
    et que Ma classe principale hérite de la classe à part (LoadProgTvData) ?
    Et redefinir le OnCreate dans la classe principale...
    (car plusieurs Activity implemente ma classe LoadProgTvData actuellement)

  7. #7
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Tu peux aussi faire un Handler sur ta ListRefresher . Ou l'activity en cours se liera avec cet handler pour récupérer les messages envoyés, En fonction du message tu sauras si tu dois afficher ou détruire la progress , de plus cet handler peut te permettre de faire autre chose , comme gérer les messages d'erreur à partir de ton activity .

    Voilà cela reste qu'une idée

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Tu peux aussi faire un Handler sur ta ListRefresher . Ou l'activity en cours se liera avec cet handler pour récupérer les messages envoyés, En fonction du message tu sauras si tu dois afficher ou détruire la progress , de plus cet handler peut te permettre de faire autre chose , comme gérer les messages d'erreur à partir de ton activity .

    Voilà cela reste qu'une idée
    Pourrais tu me guider via un exemple ?

  9. #9
    Rédacteur
    Avatar de MrDuChnok
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2002
    Messages
    2 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 112

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Malheuresement avec le code de la FAQ, si on change l'orientation, ça fait planter...(car relance le thread à chaque rotation)


    PS: J'ai fait un autre essai avec l'héritage de Activity, mais j'ai une nouvelle trace :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    java.lang.IllegalArgumentException: no dialog with id 0 was ever shown via Activity#showDialog
    Bien sur après une rotation...

    La classe static, inner classe de LoadProgTvData (qui extends de Activity maintenant) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    static class ListRefresher extends AsyncTask<Void, Void, Void> {
    	private boolean loadXML = true;
    	private LoadProgTvData  activity = null;		
     
    	public ListRefresher(LoadProgTvData prgActivity) {
    		attach(prgActivity);
    	}
     
    	@Override
    	protected void onPreExecute() {
    		if(!lst_prog.isEmpty())
    			loadXML = false;
    		else
    			activity.showDialog(0);
    	}
     
    	@Override
    	protected Void doInBackground(Void... params) {
    		if(loadXML)
    			activity.setListFromXml();
    		return null;
    	}
     
    	@Override
    	protected void onPostExecute(Void result) {
    		if(null != activity) {
    			if(loadXML)
    				activity.dismissDialog(0);  // Il plante à cette ligne avec la trace ci-dessus
    			activity.refreshListView();
    		}
    	}
     
    	public void detach() {
    		activity=null;
    	}
     
    	public void attach(LoadProgTvData activity) {
    		this.activity=activity;
    	}
    }
    dans le OnCreate :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    listRefresher = (ListRefresher)getLastNonConfigurationInstance();
     
    if (null == listRefresher) {
    	listRefresher = new ListRefresher(this);
    	listRefresher.execute();
    } else {
    listRefresher.attach(this);
    }
    et :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public Object onRetainNonConfigurationInstance() {
    	listRefresher.detach();
    	return listRefresher;
    }

  11. #11
    Rédacteur
    Avatar de MrDuChnok
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2002
    Messages
    2 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 112
    Par défaut
    Oui, je sais bien, mais il est a adapter en fonction de ton besoin.

    Là ici, si je comprend bien ton problème :
    une instance A de Activity1 lance une progressDialog (basé sur le context de A).
    Tu effectue une rotation
    l'instance A est détruite, et une nouvelle instance B (d'Activity1) est créée.
    Lorsque tu veux détruire ta progressDialog, tu essayes de le faire depuis B, or B n'a pas le même context, et donc n'est pas autorisé à détruire ta progressDialog.

    As tu essayé de construire ta progressDialog en te basant non pas sur le context de ton activité mais sur le context de ton application ?
    Celui ci ne devrait pas changer, et donc tu devrais pouvoir détruire ta dialog quoi qu'il se passe sur tes activités.

    http://developer.android.com/referen...lication%28%29

    (je me suis basé que sur des suppositions, donc je sais pas si ça va marcher, mais personnellement, j'aurai testé un truc du genre )

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Je viens d'essayer avec :
    loadingDialog = new ProgressDialog(getApplication());
    mais j'ai la trace suivante (et ça plante) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.TabProgTv}: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.ProgTv}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
    Mais a priori ça ne devrai pas marcher, car il ne saura pas à quelle vue rattacher la ProgressDialog...

    Le fonctionnement est ainsi :
    Il crée l'Activity A, il lance une tache asynchrone (AsyncTask) qui prends en paramètre l'activity A et lance la progressDialog + mon long traitement.
    On fait un rotation
    Il crée l'Activity B, il vérifie si une tache existe, si oui, il met à jour son activity.

    Malheuresement ce qui a pas l'air de lui plaire c'est que je n'ai pas fait appel à showDialog dans B (et qu'il fasse appel à dismissDialog par contre).


    Sinon j'ai toujours ma solution "pas propre", mettre un try catch autour du dismissDialog pour ne pas gérer son exception...

  13. #13
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Dans ce cas crée un Handler dans la classe LoadProgTvData .

    Donne le context de ListRefresher à LoadProgTvData pour qu'il puisse lui renvoyer les messages.

    Met le à nul lorsque tu ne veux plus recevoir de message .

    Défini un protocole pour lui annoncé l'affichage ou la destruction de ta progress soit
    0 : affichage
    1 : destruction
    2 : ...

    Et garde ta progress en mémoire dans la classe ListRefresher où tu gérera son affichage via un onCreateDialog et onPrepareDialog .

Discussions similaires

  1. WebI BO XI changement d'orientation du text
    Par atb dans le forum Webi
    Réponses: 6
    Dernier message: 06/05/2008, 16h42
  2. Changement d'orientation professionnelle
    Par y_a_b dans le forum Emploi
    Réponses: 2
    Dernier message: 23/01/2008, 16h12
  3. [TCPDF] changement d'orientation portrait/paysage
    Par Pixys dans le forum Bibliothèques et frameworks
    Réponses: 8
    Dernier message: 22/12/2007, 22h46
  4. Réponses: 10
    Dernier message: 08/09/2006, 09h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo