Activity 在使用 volley 时泄漏了窗口

Posted

技术标签:

【中文标题】Activity 在使用 volley 时泄漏了窗口【英文标题】:Activity has leaked window while using volley 【发布时间】:2017-01-12 23:01:36 【问题描述】:

我正在使用 volley 库中的 JSONRequest,在后台作为 Asynctask() ...

public class DataTask extends AsyncTask<String, Void, Void> 
    public static ProgressDialog pd;
    ...

    public DataTask(Context ctx,...) 
    ...
        pd = new ProgressDialog(context);
       ...
    

    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        pd.setTitle("Please wait...");
        pd.show();
    

    @Override
    protected Void doInBackground(String... params) 
        ...
        Log.d(TAG, " url=" + url);
        JSONRequest jsonObjReq = new JSONRequest(Request.Method.GET, url, null,
                 new Response.Listener<JSONObject>() 
            @Override
            public void onResponse(JSONObject response) 
                ...
                if (response.equals("success")) 
                ...
                else if(response.equals("fail"))
                    // logout the user and redirect to login screen
                
                Log.d(TAG, " -> pd.isShowing() = " + pd.isShowing());
                if (pd.isShowing())  pd.hide(); 
                ...
            
        , new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 
                error.printStackTrace();
                pd.hide();
            
        );
        ...
        // Adding request to request queue
        App.Instance().addToQueue(jsonObjReq);
        return null;
    

    @Override
    protected void onPostExecute(Void data) ...


我得到的错误是......

....
E/WindowManager: android.view.WindowLeaked: Activity com.volley.exmpl.DataViewActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView3d416b1c V.E..... R......D 0,0-729,324 that was originally added here
                     at android.view.ViewRootImpl.<init>(ViewRootImpl.java:363)
                     at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:271)
                     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
                     at android.app.Dialog.show(Dialog.java:298)
                     at com.volley.exmpl.Task.LoginTask.onPreExecute(LoginTask.java:43)
                     at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:591)
                     at android.os.AsyncTask.execute(AsyncTask.java:539)
                     at com.volley.exmpl.DataViewActivity.callLogin(DataViewActivity.java:281)
                     at com.volley.exmpl.DataViewActivity.ondataViewCompleted(DataViewActivity.java:283)
                     at com.volley.exmpl.Task.DataTask$1.onResponse(DataTask.java:210)
                     at com.volley.exmpl.Task.DataTask$1.onResponse(DataTask.java:112)
                     at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:68)
                     at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:113)
                     at android.os.Handler.handleCallback(Handler.java:739)
                     at android.os.Handler.dispatchMessage(Handler.java:95)
                     at android.os.Looper.loop(Looper.java:135)
                     at android.app.ActivityThread.main(ActivityThread.java:5254)
                     at java.lang.reflect.Method.invoke(Native Method)
                     at java.lang.reflect.Method.invoke(Method.java:372)
                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
D/TAG_Act: onStop()-> className::close ListActivity
D/AndroidRuntime: Shutting down VM
....
                  --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.volley.exmpl, PID: 29825
                  java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView3d416b1c V.E..... R......D 0,0-729,324 not attached to window manager
                      at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:396)
                      at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:322)
                      at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:116)
                      at android.app.Dialog.dismissDialog(Dialog.java:341)
                      at android.app.Dialog.dismiss(Dialog.java:324)
                      at com.volley.exmpl.Task.LoginTask$1.onResponse(LoginTask.java:120)
                      at com.volley.exmpl.Task.LoginTask$1.onResponse(LoginTask.java:71)
                      at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:68)
                      at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:113)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:135)
                      at android.app.ActivityThread.main(ActivityThread.java:5254)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:372)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

任何想法,...

我已经阅读了https://***.com/a/2850597/3099185 的答案,我发现这有点相关,但无法找到适合我情况的解决方案

还有 another link is available ,但我不能这样概括,因为我的每个班级处理数据的方式不同!?!??!!?

谢谢,提前!

【问题讨论】:

由于这个 ava.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView3d416b1c VE.... R...... D 0,0-729,324 未附加到窗口管理器,点击 logcat 并查看导致崩溃的方法。 根据代码,如果您在else if(response.equals("fail")) // logout the user and redirect to login screen 看到另一个 loginTask.java 被称为具有与 DataTask.java public class DataTask extends AsyncTask&lt;String, Void, Void&gt; 相同的结构...有时我只会从中得到错误,我有点像它试图访问ProgressDialog pd,但直到任务完成并且活动也已更改... 【参考方案1】:

onPostExecute()中写入if(pd.isShowing()) pd.hide(); ,并从doInBackground()中删除所有与progressDialog相关的语句。

此错误是因为在 AsyncTask onPreExecute()onPostExecute() 上运行 main threaddoInBackground() 在不同的 thread 上运行。如果您将处理来自另一个thread 而不是Main ThreadUI 相关操作,那么您的窗口将被泄露。

【讨论】:

我也试过了,在这种情况下,pd 会在pd.show() 的几毫秒内关闭,因为 JSONRequest 是在后台单独处理的,根据 volley,postExecution( ) 将在我在..new Response.Listener&lt;JSONObject&gt;() @Override public void onResponse(JSONObject response) ... if (response.equals("success")) 中获得数据时更早地被调用... :( 因此,如果我在 `Response.Listener() ..` 或, new Response.ErrorListener() 中遇到任何错误或异常...用户会感到困惑,因为progreesDialog 是较早关闭,但屏幕没有更新新数据......所以他执行了一些其他操作,意味着没有先前请求的数据,他试图提出越来越多的请求...... 感谢您的回答。这个答案可能很有用,但我的 cas 有点不同。而且我发现 Retrofit 比 Volley 更好更快。接受您的答案,因为它与执行堆栈优化更相关。【参考方案2】:

@Bhuro 我在寻找类似问题的解决方案时遇到了这个问题。我设法得到了解决方案,错误实际上是使用 pDialog.hide() 而不是 pDialog.dismiss()。万一其他人遇到这样的问题,初始化进度对话框如下;

ProgressDialog pDialog=new ProgressDialog(YourActivity.this);

然后在 volley Response 方法或 Error 方法中将其关闭,然后再退出 jsonRequest 方法,就像在上面的 OP 问题的代码中一样。我的 pDialog 方法如下;

private void showDialog()
    if(!pDialog.isShowing())
        pDialog.show();


private void hideDialog()
    if(pDialog.isShowing())
        pDialog.dismiss();

另外,我在Activity的onDestroy方法中调用了dismiss方法;

  @Override
public void onDestroy()
    super.onDestroy();
    if(pDialog!=null)
        hideDialog();
    

【讨论】:

感谢您的回答,我的 asynctask 类在不同的包中,而您的在同一个活动中。所以不能用于我的应用程序。顺便说一句,我已经改变了我对使用 Volly => Retrofit 的偏好......但这对初学者很有用......

以上是关于Activity 在使用 volley 时泄漏了窗口的主要内容,如果未能解决你的问题,请参考以下文章

解读在Activity中使用Handler的内存泄漏问题

Volley

Android开发常见的Activity中内存泄漏及解决办法

Android开发常见的Activity中内存泄漏及解决办法

Android性能优化之内存泄漏

android内存泄漏