android - 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
}
任何指向我应该更改哪里和哪个文件来解决这个问题的指针?
需要的任何其他代码、日志或详细信息,请在评论中告诉我,我会提供。
解决方案
这个构造函数是错误的
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 Thread
s、executors 等)
推荐阅读
- c - 哪个结构用于从 REG_FULL_RESOURCE_DESCRIPTOR 类型的注册表值数据中提取信息?
- javascript - 选择列表/菜单选项时需要一个文本字段
- c# - 如何将复合类型传递给 PL/pgsql 函数?
- python - 使用 python 和 obspy 抽取文件
- vba - 使用 VBA 搜索和复制 Excel 数据
- revit-api - Python 中的 Revit API 更改组
- object - TclOO:对象等于
- sql-server - 定义时间范围内的分钟利用率 - T-SQL
- java - JMeter - 从主设备运行 JMeter 从设备会导致 RMI 连接异常
- java - Java:围绕“+”拆分字符串