android - servicio - Vista no conectada al bloqueo del administrador de ventanas
servicio aero windows 7 (13)
Anula el Destrucción de la Actividad y Descarta tu Diálogo y hazlo nulo
protected void onDestroy ()
{
if(mProgressDialog != null)
if(mProgressDialog.isShowing())
mProgressDialog.dismiss();
mProgressDialog= null;
}
Estoy usando ACRA para informar bloqueos de aplicaciones. pDialog.dismiss();
mensaje de error View not attached to window manager
y pensé que lo había solucionado envolviendo el pDialog.dismiss();
en una declaración if:
if (pDialog!=null)
{
if (pDialog.isShowing())
{
pDialog.dismiss();
}
}
Se ha reducido la cantidad de View not attached to window manager
bloqueos del View not attached to window manager
que recibo, pero sigo recibiendo algunas y no estoy seguro de cómo resolverlas.
Mensaje de error:
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)
Fragmento de código:
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);
}
}
Manifiesto:
<activity
android:name="pagename.CLASS"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"
android:label="@string/name" >
</activity>
¿Qué me estoy perdiendo para evitar que ocurra este accidente?
Basado en @erakitin answer, pero también compatible para las versiones de Android <API level 17. Tristemente Activity.isDestroyed() solo es compatible desde el nivel 17 de la API, por lo que si estás segmentando un nivel de API anterior como yo, tendrás que compruébalo tú mismo. Después de eso, no obtuve la View not attached to window manager
excepción del View not attached to window manager
.
Código de ejemplo
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
}
}
}
El problema podría ser que la Activity
haya finished
o esté en progress of finishing
.
Agregar un cheque es isFinishing
y descartar el diálogo solo cuando esto es false
if (!YourActivity.this.isFinishing() && pDialog != null) {
pDialog.dismiss();
}
isFinishing: compruebe si esta actividad está en proceso de finalización, ya sea porque llamó para finish
o porque alguien más la solicitó.
En primer lugar, el motivo del bloqueo es que el índice de decorView es -1, podemos conocerlo desde el código fuente de Android, hay un fragmento de código:
clase: android.view.WindowManagerGlobal
archivo: WindowManagerGlobal.java
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;
}
así que obtenemos la resolución de seguimiento, solo juzgue el índice de decorView, si es más que 0, luego continúe o simplemente devuelva y desista, deséchelo de la siguiente manera:
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();
}
Este problema se debe a que su actividad finaliza antes de que se llame a la función de descartar. Maneje la excepción y verifique su registro ADB por el motivo exacto.
/**
* 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);
}
Para el Dialog
creado en un Fragment
, utilizo el siguiente código:
ProgressDialog myDialog = new ProgressDialog(getActivity());
myDialog.setOwnerActivity(getActivity());
...
Activity activity = myDialog.getOwnerActivity();
if( activity!=null && !activity.isFinishing()) {
myDialog.dismiss();
}
Uso este patrón para tratar el caso cuando un Fragment
puede ser separado de la Activity
.
Puede ser que inicialice pDialog globalmente, luego quítelo e inicialice su vista o diálogo localmente. Tengo el mismo problema, lo he hecho y mi problema se ha resuelto. Espero que funcione para ti.
Reemplazar aConfigurationChanged y descartar el diálogo de progreso. Si el diálogo de progreso se crea en vertical y se descarta en el paisaje, arrojará la vista no asociada al error del administrador de ventanas.
Además, detenga la barra de progreso y detenga la tarea asincrónica en los métodos onPause (), onBackPressed y onDestroy.
if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){
asyncTaskObj.cancel(true);
}
Tengo una forma de reproducir esta excepción.
Yo uso 2 AsyncTask
. Una tarea larga y otra una tarea corta. Después de completar la tarea corta, llame a finish()
. Cuando la tarea larga se completa y llama a Dialog.dismiss()
, se bloquea.
Aquí está mi código de muestra:
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");
}
}
Puedes probar esto y descubrir cuál es la mejor manera de solucionar este problema. De mi estudio, hay al menos 4 formas de solucionarlo:
- @ erakitin''s answer: call
isFinishing()
para verificar el estado de la actividad - @ Respuesta de Kapé: establecer bandera para verificar el estado de la actividad
- Use try / catch para manejarlo.
- Llame a
AsyncTask.cancel(false)
enonDestroy()
. Evitará que la asynctask se ejecute enonPostExecute()
pero ejecuteonCancelled()
lugar.
Nota:onPostExecute()
se ejecutará incluso si llama aAsyncTask.cancel(false)
en el sistema operativo Android anterior, como Android 2.XX
Puedes elegir el mejor para ti.
Vea cómo funciona el código aquí:
Después de llamar a la tarea Async, la tarea asíncrona se ejecuta en segundo plano. eso es deseable Ahora esta tarea Async tiene un diálogo de progreso que se adjunta a la Actividad, si le preguntas cómo, mira el código:
pDialog = new ProgressDialog(CLASS.this);
Estás pasando la Class.this
es un contexto del argumento. Por lo tanto, el cuadro de diálogo Progreso aún está adjunto a la actividad.
Ahora considere el escenario: si tratamos de terminar la actividad usando el método finish (), mientras la tarea asincrónica está en progreso, es el punto donde intenta acceder al Recurso adjunto a la actividad, es decir, la progess bar
cuando la actividad no es más allí.
Por lo tanto, obtienes:
java.lang.IllegalArgumentException: View not attached to window manager
.
Solución a esto:
1) Asegúrese de que el cuadro de diálogo se cierre o se cancele antes de que la actividad finalice.
2) Finalice la actividad, solo después de cerrar el cuadro de diálogo, que es la tarea asíncrona terminada.
mejor solución. El primer contexto de la consulta es el contexto de la actividad o el contexto de la aplicación si el contexto de la actividad solo comprueba si la actividad finalizó o no, entonces llama a dialog.show()
o dialog.dismiss();
Vea el código de muestra a continuación ... ¡espero que sea útil!
Mostrar diálogo
if (context instanceof Activity) {
if (!((Activity) context).isFinishing())
dialog.show();
}
Descartar el diálogo
if (context instanceof Activity) {
if (!((Activity) context).isFinishing())
dialog.dismiss();
}
Si desea agregar más controles, agregue dialog.isShowing()
o dialog !-null
usando &&
condition.
Cómo reproducir el error:
- Habilite esta opción en su dispositivo:
Settings -> Developer Options -> Don''t keep Activities
. - Presione el botón de Inicio mientras se está ejecutando
AsyncTask
y se muestraProgressDialog
.
El sistema operativo Android destruirá una actividad tan pronto como esté oculta. Cuando se llama a onPostExecute
la Activity
estará en estado de "finalización" y ProgressDialog
no se adjuntará a la Activity
.
Como arreglarlo:
- Compruebe el estado de la actividad en su método
onPostExecute
. - Descartar el
ProgressDialog
en el métodoonDestroy
. De lo contrario, se lanzará la excepciónandroid.view.WindowLeaked
. Esta excepción generalmente proviene de diálogos que aún están activos cuando la actividad está finalizando.
Prueba este código fijo:
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);
}
}
}
@Override
public void onPause() {
super.onPause();
if(pDialog != null)
pDialog .dismiss();
pDialog = null;
}
referir this