Aller au contenu

ProgressDialog & AsyncTask + Changement d'orientation


Aure77

Recommended Posts

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:

// 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 :

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...).

Lien vers le commentaire
Partager sur d’autres sites

Je crois que tu n'as pas lu la première ligne en commentaire dans mon code, j'ai mis dans le manifest :

android:configChanges="keyboardHidden|orientation" (et pas rotation)

Mais malheuresement ce n'est pas le problème... le problème est que "progressDialog.dismiss();" leve une exception (NullPointer...) quand il est appellé (notamment après une rotation).

Je pense que c'est du au fait que le context ne soit plus le même qui lui pose problème.

Lien vers le commentaire
Partager sur d’autres sites

ha oui désolé :P

Alors déjà un truc, il me semble qu'on ne peut pas faire appel plusieurs fois à setContentView() dans la vie d'une Activity (mais je ne suis pas sûr)

Le mieux, ça serait quand même que tu nous dises quelle ligne pose problème... (trace....)

Lien vers le commentaire
Partager sur d’autres sites

J'ai fait l'implementation comme via le lien de Nivek (j'ai gardé ma ProgressDialog au lieu de ProgressBar)

Mais j'ai toujours le même problème.... voici la trace :

ERROR/AndroidRuntime(648): java.lang.IllegalArgumentException: no dialog with id 0 was ever shown via Activity#showDialog

Cette erreur intervient bien sur après une rotation de l'écran...

La classe static, inner classe de LoadProgTvData (qui extends de Activity maintenant) :

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 ProgTvActivity extends Activity j'ai rajouté :


private ProgressDialog loadingDialog = null;
@Override
protected Dialog onCreateDialog(int id) {
if(id == 0){
	loadingDialog = new ProgressDialog(this);
	loadingDialog.setMessage("Chargement en cours...");
	loadingDialog.setIndeterminate(true);
	loadingDialog.setCancelable(true);
	return loadingDialog;
} 
return super.onCreateDialog(id);
}

Lien vers le commentaire
Partager sur d’autres sites

Ce qui te manque, c'est qu'il te faut recréer ta boite de dialogue dans ton onResume si tu détectes que tu es dans le cas d'une rotation d'écran (getLastNonConfigurationInstance() qui retourne non-null). Car si Android recrée une Activity en cas de rotation, ce ne doit pas être le cas d'une boite de dialogue...

Lien vers le commentaire
Partager sur d’autres sites

Y'a un truc qui me chiffonne, c'est que si tu as mis un android:configChanges dans ton manifest.xml, alors tu ne devrais pas avoir ce problème, et Android ne devrait pas détruire ton Activity et la Dialog qui va avec lors d'un changement d'orientation

Par contre, sur quelle activity as-tu mis cet attribut android:configChanges ? si je comprends bien à la relecture de ton premier post, tu as une TabActivity qui contient des onglets, dont ton Activity détaillée ici... Il faut que le android:configChanges soit sur la TabActivity, s'il est sur l'autre cela ne sert à rien, car sinon c'est la TabActivity qui est détruire/recréée, et par conséquence ses Activity filles aussi, lors d'un changement de configuration.

Si c'est le cas, fais le changement et tu pourras te passer des onConfigurationChanged/onRetainNonConfigurationIntance/...

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...