J'utilise ACRA pour signaler les plantages d'applications. Je recevais un View not attached to window manager
message d'erreur et je pensais l'avoir corrigé en enveloppant le pDialog.dismiss();
dans une instruction if:
if (pDialog!=null)
{
if (pDialog.isShowing())
{
pDialog.dismiss();
}
}
Cela a réduit le nombre d' View not attached to window manager
accidents que je reçois, mais j'en reçois toujours et je ne sais pas comment le résoudre.
Message d'erreur:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:425)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:327)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:83)
at android.app.Dialog.dismissDialog(Dialog.java:330)
at android.app.Dialog.dismiss(Dialog.java:312)
at com.package.class$LoadAllProducts.onPostExecute(class.java:624)
at com.package.class$LoadAllProducts.onPostExecute(class.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
Extrait de code:
class LoadAllProducts extends AsyncTask<String, String, String>
{
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = new ProgressDialog(CLASS.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
// Building Parameters
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
// dismiss the dialog after getting all products
if (pDialog!=null)
{
if (pDialog.isShowing())
{
pDialog.dismiss(); //This is line 624!
}
}
something(note);
}
}
Manifeste:
<activity
android:name="pagename.CLASS"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"
android:label="@string/name" >
</activity>
Que me manque-t-il pour empêcher ce crash de se produire?
AsyncTask
est déclaré à l'intérieurActivity
ouFragment
?Réponses:
Comment reproduire le bogue:
Settings -> Developer Options -> Don't keep Activities
.AsyncTask
exécution de et queProgressDialog
s'affiche.Le système d'exploitation Android détruira une activité dès qu'elle sera masquée. Quand
onPostExecute
est appelé, leActivity
testament sera en état de "finition" et leProgressDialog
sera non attachéActivity
.Comment le réparer:
onPostExecute
méthode.ProgressDialog
inonDestroy
. Sinon, uneandroid.view.WindowLeaked
exception sera levée. Cette exception provient généralement des boîtes de dialogue qui sont toujours actives lorsque l'activité se termine.Essayez ce code fixe:
public class YourActivity extends Activity { private void showProgressDialog() { if (pDialog == null) { pDialog = new ProgressDialog(StartActivity.this); pDialog.setMessage("Loading. Please wait..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); } pDialog.show(); } private void dismissProgressDialog() { if (pDialog != null && pDialog.isShowing()) { pDialog.dismiss(); } } @Override protected void onDestroy() { dismissProgressDialog(); super.onDestroy(); } class LoadAllProducts extends AsyncTask<String, String, String> { // Before starting background thread Show Progress Dialog @Override protected void onPreExecute() { showProgressDialog(); } //getting All products from url protected String doInBackground(String... args) { doMoreStuff("internet"); return null; } // After completing background task Dismiss the progress dialog protected void onPostExecute(String file_url) { if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17 return; } dismissProgressDialog(); something(note); } } }
la source
isDestroyed()
overisFinishing()
sur toutes les API à cette fin spécifique?isFinishing()
n'est pas garantitrue
si l'activité est détruite par le système, voir la documentation sur les activités .// or call isFinishing() if min sdk version < 17
, il se heurte à la même exception. Nous avons donc besoin d'une solution différente de celle-ci pour les applications exécutées sur API <17.myActivityWeakReference.get() != null && !myActivityWeakReference.get().isFinishing()
Le problème pourrait être que le
Activity
fichier a étéfinished
ou est entréprogress of finishing
.Ajoutez une coche
isFinishing
et fermez la boîte de dialogue uniquement lorsquefalse
if (!YourActivity.this.isFinishing() && pDialog != null) { pDialog.dismiss(); }
isFinishing: vérifiez si cette activité est en cours de fin, soit parce que vous l'avez appelée, soit parce que
finish
quelqu'un d'autre a demandé qu'elle se termine.la source
Pour
Dialog
créé en aFragment
, j'utilise le code suivant:ProgressDialog myDialog = new ProgressDialog(getActivity()); myDialog.setOwnerActivity(getActivity()); ... Activity activity = myDialog.getOwnerActivity(); if( activity!=null && !activity.isFinishing()) { myDialog.dismiss(); }
J'utilise ce modèle pour traiter le cas où un
Fragment
peut être détaché duActivity
.la source
Voyez comment le code fonctionne ici:
Après avoir appelé la tâche Async, la tâche async s'exécute en arrière-plan. c'est souhaitable. Maintenant, cette tâche Async a une boîte de dialogue de progression qui est attachée à l'activité, si vous demandez comment voir le code:
pDialog = new ProgressDialog(CLASS.this);
Vous transmettez le
Class.this
contexte à l'argument. Ainsi, la boîte de dialogue Progression est toujours associée à l'activité.Considérons maintenant le scénario: si nous essayons de terminer l'activité en utilisant la méthode finish (), alors que la tâche asynchrone est en cours, c'est le point où vous essayez d'accéder à la ressource attachée à l'activité, c'est-à-dire le
progress bar
moment où l'activité n'est plus Là.Par conséquent, vous obtenez:
java.lang.IllegalArgumentException: View not attached to the window manager
Solution à ceci:
1) Assurez-vous que la boîte de dialogue est fermée ou annulée avant la fin de l'activité.
2) Terminez l'activité, uniquement après la fermeture de la boîte de dialogue, c'est-à-dire que la tâche asynchrone est terminée.
la source
Activity
; Android peut le terminer à tout moment. Donc, # 2 n'a pas de sens.Basé sur la réponse @erakitin, mais également compatible pour les versions d'Android <API niveau 17. Malheureusement, Activity.isDestroyed () n'est pris en charge qu'à partir du niveau API 17, donc si vous ciblez un niveau d'API plus ancien comme moi, vous devrez vérifiez-le vous-même. Je n'ai pas eu l'
View not attached to window manager
exception après ça.Exemple de code
public class MainActivity extends Activity { private TestAsyncTask mAsyncTask; private ProgressDialog mProgressDialog; private boolean mIsDestroyed; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (condition) { mAsyncTask = new TestAsyncTask(); mAsyncTask.execute(); } } @Override protected void onResume() { super.onResume(); if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) { Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show(); return; } } @Override protected void onDestroy() { super.onDestroy(); mIsDestroyed = true; if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> { @Override protected void onPreExecute() { super.onPreExecute(); mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff.."); } @Override protected AsyncResult doInBackground(Void... arg0) { // Do long running background stuff return null; } @Override protected void onPostExecute(AsyncResult result) { // Use MainActivity.this.isDestroyed() when targeting API level 17 or higher if (mIsDestroyed)// Activity not there anymore return; mProgressDialog.dismiss(); // Handle rest onPostExecute } } }
la source
@Override public void onPause() { super.onPause(); if(pDialog != null) pDialog .dismiss(); pDialog = null; }
renvoyer ceci .
la source
Remplacez onConfigurationChanged et fermez la boîte de dialogue de progression. Si la boîte de dialogue de progression est créée en portrait et disparaît en paysage, elle lancera une erreur Vue non attachée au gestionnaire de fenêtres.
Arrêtez également la barre de progression et arrêtez la tâche asynchrone dans les méthodes onPause (), onBackPressed et onDestroy.
if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){ asyncTaskObj.cancel(true); }
la source
Remplacer onDestroy de l'activité et ignorer votre boîte de dialogue et la rendre nulle
protected void onDestroy () { if(mProgressDialog != null) if(mProgressDialog.isShowing()) mProgressDialog.dismiss(); mProgressDialog= null; }
la source
Tout d'abord, la raison du crash est que l'index de decorView est -1, nous pouvons le savoir à partir du code source Android, il y a un extrait de code:
private int findViewLocked(View view, boolean required) { final int index = mViews.indexOf(view); //here, view is decorView,comment by OF if (required && index < 0) { throw new IllegalArgumentException("View=" + view + " not attached to window manager"); } return index; }
nous obtenons donc une résolution de suivi, il suffit de juger l'index de decorView, s'il est supérieur à 0, continuez ou retournez simplement et abandonnez le code comme suit:
try { Class<?> windowMgrGloable = Class.forName("android.view.WindowManagerGlobal"); try { Method mtdGetIntance = windowMgrGloable.getDeclaredMethod("getInstance"); mtdGetIntance.setAccessible(true); try { Object windownGlobal = mtdGetIntance.invoke(null,null); try { Field mViewField = windowMgrGloable.getDeclaredField("mViews"); mViewField.setAccessible(true); ArrayList<View> mViews = (ArrayList<View>) mViewField.get(windownGlobal); int decorViewIndex = mViews.indexOf(pd.getWindow().getDecorView()); Log.i(TAG,"check index:"+decorViewIndex); if (decorViewIndex < 0) { return; } } catch (NoSuchFieldException e) { e.printStackTrace(); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } if (pd.isShowing()) { pd.dismiss(); }
la source
Remplacez la
dismiss()
méthode comme ceci:@Override public void dismiss() { Window window = getWindow(); if (window == null) { return; } View decor = window.getDecorView(); if (decor != null && decor.getParent() != null) { super.dismiss(); } }
Pour reproduire le problème, terminez simplement l'activité avant de fermer la boîte de dialogue.
la source
meilleure solution. Vérifier que le premier contexte est le contexte de l'activité ou le contexte de l'application si le contexte de l'activité, puis uniquement vérifier que l'activité est terminée ou non, puis appeler
dialog.show()
oudialog.dismiss();
if (context instanceof Activity) { if (!((Activity) context).isFinishing()) dialog.show(); }
if (context instanceof Activity) { if (!((Activity) context).isFinishing()) dialog.dismiss(); }
Si vous souhaitez ajouter plus de contrôles, ajoutez
dialog.isShowing()
oudialog !-null
utilisez une&&
condition.la source
Ce problème est dû au fait que votre activité est terminée avant que la fonction de rejet ne soit appelée. Gérez l'exception et vérifiez votre journal ADB pour la raison exacte.
/** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { try { if (pDialog!=null) { pDialog.dismiss(); //This is line 624! } } catch (Exception e) { // do nothing } something(note); }
la source
J'ai eu un moyen de reproduire cette exception.
J'utilise 2
AsyncTask
. L'un effectue une tâche longue et l'autre une tâche courte. Une fois la tâche courte terminée, appelezfinish()
. Lorsque la tâche longue est terminée et appeléeDialog.dismiss()
, elle se bloque.Voici mon exemple de code:
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ProgressDialog mProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate"); new AsyncTask<Void, Void, Void>(){ @Override protected void onPreExecute() { mProgressDialog = ProgressDialog.show(MainActivity.this, "", "plz wait...", true); } @Override protected Void doInBackground(Void... nothing) { try { Log.d(TAG, "long thread doInBackground"); Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { Log.d(TAG, "long thread onPostExecute"); if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); mProgressDialog = null; } Log.d(TAG, "long thread onPostExecute call dismiss"); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new AsyncTask<Void, Void, Void>(){ @Override protected Void doInBackground(Void... params) { try { Log.d(TAG, "short thread doInBackground"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Log.d(TAG, "short thread onPostExecute"); finish(); Log.d(TAG, "short thread onPostExecute call finish"); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); } }
Vous pouvez essayer ceci et découvrir quelle est la meilleure façon de résoudre ce problème. D'après mon étude, il existe au moins 4 façons de résoudre ce problème:
isFinishing()
pour vérifier l'état de l'activitéAsyncTask.cancel(false)
àonDestroy()
. Cela empêchera l'exécution de l'asynctaskonPostExecute()
mais s'exécutera à laonCancelled()
place.Remarque:
onPostExecute()
exécutera toujours même si vous appelezAsyncTask.cancel(false)
sur un ancien système d'exploitation Android, comme Android 2.XXVous pouvez choisir le meilleur pour vous.
la source
Peut-être initialisez-vous pDialog globalement, puis supprimez-le et initialisez votre vue ou votre boîte de dialogue localement.J'ai le même problème, j'ai fait cela et mon problème est résolu. J'espère que cela fonctionnera pour vous.
la source
nous avons également ignoré notre dialogue sur la
onPause
méthode ou laonDestroy
méthode@Override protected void onPause() { super.onPause(); dialog.dismiss(); } @Override protected void onDestroy() { super.onDestroy(); dialog.dismiss(); }
la source