首页 > 解决方案 > Activity 已泄露窗口 com.android.internal.policy.impl.PhoneWindow$DecorView{3dd12f3a VE.... R......D 0,0-1026,348}

问题描述

在以下 Android 应用程序开发错误中有点迷失。

我在测试 Android 手机时遇到的错误是“不幸的是,已停止”

可用的日志如下(在 Android Studio 的 LogCat 中可用):

2021-11-10 19:16:13.970 9937-9937/com.example.phprestsqlapp E/WindowManager: android.view.WindowLeaked: Activity com.example.phprestsqlapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{3dd12f3a V.E..... R......D 0,0-1026,348} that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:364)
        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.example.phprestsqlapp.MainActivity$ServiceStubAsyncTask.onPreExecute(MainActivity.java:61)
        at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:591)
        at android.os.AsyncTask.execute(AsyncTask.java:539)
        at com.example.phprestsqlapp.MainActivity.onCreate(MainActivity.java:40)
        at android.app.Activity.performCreate(Activity.java:6033)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2397)
        at android.app.ActivityThread.access$800(ActivityThread.java:151)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1310)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5268)
        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:902)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)

这是我的 MainActivity.java 文件:

package com.example.phprestsqlapp;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.HashMap;


public class MainActivity extends AppCompatActivity {
    private String apiPath = "https://<site.com>sample.php";
    private ProgressDialog processDialog;
    private JSONArray restulJsonArray;
    private int success = 0;

    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.mobile_name_list);
        new ServiceStubAsyncTask(this, this).execute();
    }

    private class ServiceStubAsyncTask extends AsyncTask<Void, Void, Void> {

        private Context mContext;
        private Activity mActivity;
        String response = "";
        HashMap<String, String> postDataParams;

        public ServiceStubAsyncTask(Context context, Activity activity) {
            mContext = context;
            mActivity = activity;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            processDialog = new ProgressDialog(mContext);
            processDialog.setMessage("Please  Wait ...");
            processDialog.setCancelable(false);
            processDialog.show();
        }

        @Override
        protected Void doInBackground(Void... arg0) {

            postDataParams = new HashMap<String, String>();
            postDataParams.put("HTTP_ACCEPT", "application/json");

            HttpConnectionService service = new HttpConnectionService();
            response = service.sendRequest(apiPath, postDataParams);
            try {
                success = 1;
                JSONObject resultJsonObject = new JSONObject(response);
                restulJsonArray = resultJsonObject.getJSONArray("output");
            } catch (JSONException e) {
                success = 0;
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            if (processDialog.isShowing()) {
                processDialog.dismiss();
            }

            if (success == 1) {
                if (null != restulJsonArray) {
                    ArrayAdapter listViewAdapter = new ArrayAdapter<String>(mContext, R.layout.mobile_name_listview);

                    for (int i = 0; i < restulJsonArray.length(); i++) {
                        try {
                            JSONObject jsonObject = restulJsonArray.getJSONObject(i);
                            listViewAdapter.add(jsonObject.get("name"));
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                    listView.setAdapter(listViewAdapter);
                }
            }
        }


    }//end of async task
}

任何指向我应该更改哪里和哪个文件来解决这个问题的指针?

需要的任何其他代码、日志或详细信息,请在评论中告诉我,我会提供。

标签: android

解决方案


这个构造函数是错误的

    public ServiceStubAsyncTask(Context context, Activity activity) {
        mContext = context;
        mActivity = activity;
    }

你非常不应该离开Context/Activity保存在里面AsyncTask,这可能会导致内存泄漏(你有一个)

最简单的方法是使用WeakReference

    private WeakReference<Context> mContext;
    private WeakReference<Activity> mActivity;

    public ServiceStubAsyncTask(Context context, Activity activity) {
        mContext = new WeakReference<>(context);
        mActivity = new WeakReference<>(activity);
    }

并在里面onPostExecute做好准备,mContext.get()==null或者mActivity.get()==null,因为Activity/Context可能在此异步操作期间被杀死/销毁

顺便提一句。Activity是一个Context实例,因此可能不需要保留两个单独的变量,您可以使用单参数构造new ServiceStubAsyncTask(this)函数mActivity WeakReference

但请注意,AsyncTask已弃用,有很多更好的方法来执行后台任务(如链接在 doc coroutines、simple Threads、executors 等)


推荐阅读