“Activity 已经泄露了原本添加在这里的窗口”
Posted
技术标签:
【中文标题】“Activity 已经泄露了原本添加在这里的窗口”【英文标题】:“Activity has leaked window that was originally added here” 【发布时间】:2017-06-02 17:19:29 【问题描述】:我有以下代码,我想将 mysql 同步到 SQLITE。问题是当我点击同步按钮时会出现错误。数据正在从 Mysql 服务器传输到我的 SQLITE,但它不会出现在我将数据放在列表中的应用程序的活动中。
public class MainActivity extends ActionBarActivity
// DB Class to perform DB related operations
DBController controller = new DBController(this);
// Progress Dialog Object
ProgressDialog prgDialog;
HashMap<String, String> queryValues;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get User records from SQLite DB
ArrayList<HashMap<String, String>> userList = controller.getAllUsers();
// If users exists in SQLite DB
if (userList.size() != 0)
// Set the User Array list in ListView
ListAdapter adapter = new SimpleAdapter(MainActivity.this, userList, R.layout.view_user_entry, new String[]
"userId", "userName" , new int[] R.id.userId, R.id.userName );
ListView myList = (ListView) findViewById(android.R.id.list);
myList.setAdapter(adapter);
// Initialize Progress Dialog properties
prgDialog = new ProgressDialog(this);
prgDialog.setMessage("Transferring Data from Remote MySQL DB and Syncing SQLite. Please wait...");
prgDialog.setCancelable(false);
// BroadCase Receiver Intent Object
Intent alarmIntent = new Intent(getApplicationContext(), SampleBC.class);
// Pending Intent Object
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Alarm Manager Object
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
// Alarm Manager calls BroadCast for every Ten seconds (10 * 1000), BroadCase further calls service to check if new records are inserted in
// Remote MySQL DB
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 5000, 10 * 1000, pendingIntent);
// Options Menu (ActionBar Menu)
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
// When Options Menu is selected
@Override
public boolean onOptionsItemSelected(MenuItem item)
// Handle action bar item clicks here.
int id = item.getItemId();
// When Sync action button is clicked
if (id == R.id.refresh)
// Transfer data from remote MySQL DB to SQLite on Android and perform Sync
syncSQLiteMySQLDB();
return true;
return super.onOptionsItemSelected(item);
// Method to Sync MySQL to SQLite DB
public void syncSQLiteMySQLDB()
// Create AsycHttpClient object
AsyncHttpClient client = new AsyncHttpClient();
// Http Request Params Object
RequestParams params = new RequestParams();
// Show ProgressBar
prgDialog.show();
// Make Http call to getusers.php
client.post("http://download.grupsapte.ro/sinc/getusers.php", params, new AsyncHttpResponseHandler()
@Override
public void onSuccess(String response)
// Hide ProgressBar
prgDialog.hide();
// Update SQLite DB with response sent by getusers.php
updateSQLite(response);
// When error occured
@Override
public void onFailure(int statusCode, Throwable error, String content)
// TODO Auto-generated method stub
// Hide ProgressBar
prgDialog.hide();
if (statusCode == 404)
Toast.makeText(getApplicationContext(), "Requested resource not found", Toast.LENGTH_LONG).show();
else if (statusCode == 500)
Toast.makeText(getApplicationContext(), "Something went wrong at server end", Toast.LENGTH_LONG).show();
else
Toast.makeText(getApplicationContext(), "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]",
Toast.LENGTH_LONG).show();
);
public void updateSQLite(String response)
ArrayList<HashMap<String, String>> usersynclist;
usersynclist = new ArrayList<HashMap<String, String>>();
// Create GSON object
Gson gson = new GsonBuilder().create();
try
// Extract JSON array from the response
JSONArray arr = new JSONArray(response);
System.out.println(arr.length());
// If no of array elements is not zero
if(arr.length() != 0)
// Loop through each array element, get JSON object which has userid and username
for (int i = 0; i < arr.length(); i++)
// Get JSON object
JSONObject obj = (JSONObject) arr.get(i);
System.out.println(obj.get("userId"));
System.out.println(obj.get("userName"));
// DB QueryValues Object to insert into SQLite
queryValues = new HashMap<String, String>();
// Add userID extracted from Object
queryValues.put("userId", obj.get("userId").toString());
// Add userName extracted from Object
queryValues.put("userName", obj.get("userName").toString());
// Insert User into SQLite DB
controller.insertUser(queryValues);
HashMap<String, String> map = new HashMap<String, String>();
// Add status for each User in Hashmap
map.put("Id", obj.get("userId").toString());
map.put("status", "1");
usersynclist.add(map);
// Inform Remote MySQL DB about the completion of Sync activity by passing Sync status of Users
updateMySQLSyncSts(gson.toJson(usersynclist));
// Reload the Main Activity
reloadActivity();
catch (JSONException e)
// TODO Auto-generated catch block
e.printStackTrace();
// Method to inform remote MySQL DB about completion of Sync activity
public void updateMySQLSyncSts(String json)
System.out.println(json);
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("syncsts", json);
// Make Http call to updatesyncsts.php with JSON parameter which has Sync statuses of Users
client.post("http://download.grupsapte.ro/sinc/updatesyncsts.php", params, new AsyncHttpResponseHandler()
@Override
public void onSuccess(String response)
Toast.makeText(getApplicationContext(), "MySQL DB has been informed about Sync activity", Toast.LENGTH_LONG).show();
@Override
public void onFailure(int statusCode, Throwable error, String content)
Toast.makeText(getApplicationContext(), "Error Occured", Toast.LENGTH_LONG).show();
);
// Reload MainActivity
public void reloadActivity()
Intent objIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(objIntent);
错误如下:
01-18 12:54:59.821: E/WindowManager(2022): android.view.WindowLeaked: Activity com.prgguru.example.MainActivity has leaked window com.android.internal.policy.PhoneWindow$DecorViewa19b187 G.E...... R.....ID 0,0-1336,384 that was originally added here
01-18 12:54:59.821: E/WindowManager(2022): at android.view.ViewRootImpl.<init>(ViewRootImpl.java:565)
01-18 12:54:59.821: E/WindowManager(2022): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:326)
01-18 12:54:59.821: E/WindowManager(2022): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
01-18 12:54:59.821: E/WindowManager(2022): at android.app.Dialog.show(Dialog.java:350)
01-18 12:54:59.821: E/WindowManager(2022): at com.prgguru.example.MainActivity.syncSQLiteMySQLDB(MainActivity.java:96)
01-18 12:54:59.821: E/WindowManager(2022): at com.prgguru.example.MainActivity.onOptionsItemSelected(MainActivity.java:83)
01-18 12:54:59.821: E/WindowManager(2022): at android.app.Activity.onMenuItemSelected(Activity.java:3204)
01-18 12:54:59.821: E/WindowManager(2022): at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:353)
01-18 12:54:59.821: E/WindowManager(2022): at android.support.v7.app.ActionBarActivity.superOnMenuItemSelected(ActionBarActivity.java:244)
01-18 12:54:59.821: E/WindowManager(2022): at android.support.v7.app.ActionBarActivityDelegateICS.onMenuItemSelected(ActionBarActivityDelegateICS.java:165)
01-18 12:54:59.821: E/WindowManager(2022): at android.support.v7.app.ActionBarActivity.onMenuItemSelected(ActionBarActivity.java:130)
01-18 12:54:59.821: E/WindowManager(2022): at android.support.v7.app.ActionBarActivityDelegateICS$WindowCallbackWrapper.onMenuItemSelected(ActionBarActivityDelegateICS.java:300)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.policy.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1259)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:801)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:155)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:954)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:944)
01-18 12:54:59.821: E/WindowManager(2022): at android.widget.ActionMenuView.invokeItem(ActionMenuView.java:655)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:251)
01-18 12:54:59.821: E/WindowManager(2022): at android.view.View.performClick(View.java:5697)
01-18 12:54:59.821: E/WindowManager(2022): at android.widget.TextView.performClick(TextView.java:10826)
01-18 12:54:59.821: E/WindowManager(2022): at android.view.View$PerformClick.run(View.java:22526)
01-18 12:54:59.821: E/WindowManager(2022): at android.os.Handler.handleCallback(Handler.java:739)
01-18 12:54:59.821: E/WindowManager(2022): at android.os.Handler.dispatchMessage(Handler.java:95)
01-18 12:54:59.821: E/WindowManager(2022): at android.os.Looper.loop(Looper.java:158)
01-18 12:54:59.821: E/WindowManager(2022): at android.app.ActivityThread.main(ActivityThread.java:7225)
01-18 12:54:59.821: E/WindowManager(2022): at java.lang.reflect.Method.invoke(Native Method)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
01-18 12:54:59.821: E/WindowManager(2022): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
我知道我应该把 this.finish() 放在某个地方,但我不知道确切的位置。希望有人帮助我。
【问题讨论】:
看到这个...***.com/questions/21817888/… Activity has leaked window that was originally added的可能重复 Activity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44f72ff0 that was originally added here的可能重复 您已经创建了一个进度对话框,但您从未关闭它。当您的Activity
完成时,对话框仍然处于活动状态,因此您会收到此“活动已泄漏窗口”错误。链接的问题包含一些有用的信息。
【参考方案1】:
public void syncSQLiteMySQLDB()
// Create AsycHttpClient object
AsyncHttpClient client = new AsyncHttpClient();
// Http Request Params Object
RequestParams params = new RequestParams();
// Show ProgressBar
prgDialog = new ProgressDialog(MainActivity.this);
prgDialog.setMessage("Transferring Data from Remote MySQL DB and Syncing SQLite. Please wait...");
prgDialog.setCancelable(false);
prgDialog.show();
// Make Http call to getusers.php
client.post("http://download.grupsapte.ro/sinc/getusers.php", params, new AsyncHttpResponseHandler()
@Override
public void onSuccess(String response)
// Update SQLite DB with response sent by getusers.php
updateSQLite(response);
// When error occured
@Override
public void onFailure(int statusCode, Throwable error, String content)
// TODO Auto-generated method stub
if (statusCode == 404)
Toast.makeText(getApplicationContext(), "Requested resource not found", Toast.LENGTH_LONG).show();
else if (statusCode == 500)
Toast.makeText(getApplicationContext(), "Something went wrong at server end", Toast.LENGTH_LONG).show();
else
Toast.makeText(getApplicationContext(), "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]",
Toast.LENGTH_LONG).show();
@Override
public void onFinish()
// Hide ProgressBar
if(prgDialog.isShowing())
prgDialog.hide();
);
首先你应该声明本地进度条对象并使用 MainActivity 初始化。这也 AsyncHttpClient 有一个方法 onFinish()
将在成功或失败后调用,所以你只需要在 onfinsh 方法中隐藏你的进度条,你总是应该检查进度条是否显示所以它不会导致产生异常
【讨论】:
你应该解释你做了什么以及为什么。仅代码答案通常没有帮助。 @AxelH 感谢您的建议 :) 好的..所以错误消失了,但我不知道为什么我获取数据的列表没有被填充。【参考方案2】:试试看, 在显示进度对话框之前。检查它是否已经显示,如果是,关闭它并显示对话框。
在 syncSQLiteMySQLDB 中,您正在显示进度对话框。首先检查您是否已经有一个 prgDialog 实例及其显示。然后关闭现有的 prgDialog 并显示。并在显示之前检查活动是否未完成。
public void syncSQLiteMySQLDB()
....
if( !isFinishing())
if(prgDialog !=null)
if(prgDialog.isShowing())
prgDialog.dismiss()
prgDialog.show();
【讨论】:
为什么?什么时候 ?在哪里 ?请通过编辑您的答案来解释您的解决方案 @AxelH 感谢您的建议,伙计:)【参考方案3】:你需要dismiss
() progressDialog
@Override
public void onSuccess(String response)
// dismiss ProgressBar
if (prgDialog != null)
prgDialog.dismiss(); //not hide try dismiss the dialog
// Update SQLite DB with response sent by getusers.php
updateSQLite(response);
也在你的onFailure
方法dismiss
()dialog
【讨论】:
【参考方案4】:您正在重新加载活动而不关闭对话框,因此您应该先关闭。
public void reloadActivity()
// dissmiss dialog first then reload activity.
if(prgDialog.isShowing())
prgDialog.dismiss();
Intent objIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(objIntent);
【讨论】:
【参考方案5】:花了几分钟才发现这个内存泄漏,不需要在准备对话框构建器中使用.show
@Override
protected void onPrepareDialogBuilder(final AlertDialog.Builder builder)
builder
.setIcon(getIconImage(context))
.setTitle("title)
.setMessage("message")
.setPositiveButton("ok",
new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
start intent
)
.setNegativeButton("cancel",
new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
)
.show();
else
do something else
【讨论】:
以上是关于“Activity 已经泄露了原本添加在这里的窗口”的主要内容,如果未能解决你的问题,请参考以下文章