Android常见问题1:窗体泄露(1)

今天学习对话框AlertDialog,写一个Demo,需求是:只有一个Activitty,在这个Activity中只有一个按钮Button,当点击按钮Button时,弹出对话框,提示是否关闭该Activity,退出程序(只有一个界面).

MainActivity源码:

 1 package com.my.day22_my_dialog1;
 2
 3 import android.os.Bundle;
 4 import android.view.KeyEvent;
 5 import android.view.View;
 6 import android.view.View.OnClickListener;
 7 import android.widget.Button;
 8 import android.app.Activity;
 9 import android.app.AlertDialog;
10 import android.app.Dialog;
11 import android.content.DialogInterface;
12
13 public class MainActivity extends Activity {
14     private Button bt;
15     private AlertDialog dialog;
16
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21
22         initDialog();
23
24         bt = (Button) findViewById(R.id.bt);
25         bt.setOnClickListener(new OnClickListener() {
26
27             @Override
28             public void onClick(View v) {
29                 dialog.show();
30             }
31         });
32     }
33
34     private void initDialog() {
35         //创建对话框创建器对象
36         AlertDialog.Builder builder = new AlertDialog.Builder(this);
37
38         builder.setTitle("关闭?");
39         builder.setIcon(R.drawable.ic_launcher);
40         builder.setMessage("关闭该Activity?");
41         builder.setCancelable(false);//设置点击对话框之外的内容是否取消对话框
42         builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
43
44             @Override
45             public void onClick(DialogInterface dialog, int which) {
46                 finish();
47             }
48         });
49
50         builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
51
52             @Override
53             public void onClick(DialogInterface dialog, int which) {
54                 dialog.dismiss();
55             }
56         });
57
58
59         dialog = builder.create();
60     }
61 }

activity_man.xml布局文件:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".MainActivity" >
10
11    <Button
12        android:id="@+id/bt"
13        android:layout_width="match_parent"
14        android:layout_height="wrap_content"
15        android:text="对话框"/>
16
17 </RelativeLayout>

现在增加需求:要求点击返回键时,关闭该Activity。

方式1:

重写public boolean onKeyDown(int keyCode, KeyEvent event)方法,适合各种按键事件,可以说比较通用。

修改后的MainActivity源码:

 1 package com.my.day22_my_dialog1;
 2
 3 import android.os.Bundle;
 4 import android.view.KeyEvent;
 5 import android.view.View;
 6 import android.view.View.OnClickListener;
 7 import android.widget.Button;
 8 import android.app.Activity;
 9 import android.app.AlertDialog;
10 import android.app.Dialog;
11 import android.content.DialogInterface;
12
13 public class MainActivity extends Activity {
14     private Button bt;
15     private AlertDialog dialog;
16
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21
22         initDialog();
23
24         bt = (Button) findViewById(R.id.bt);
25         bt.setOnClickListener(new OnClickListener() {
26
27             @Override
28             public void onClick(View v) {
29                 dialog.show();
30             }
31         });
32     }
33
34     private void initDialog() {
35         //创建对话框创建器对象
36         AlertDialog.Builder builder = new AlertDialog.Builder(this);
37
38         builder.setTitle("关闭?");
39         builder.setIcon(R.drawable.ic_launcher);
40         builder.setMessage("关闭该Activity?");
41         builder.setCancelable(false);//设置点击对话框之外的内容是否取消对话框
42         builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
43
44             @Override
45             public void onClick(DialogInterface dialog, int which) {
46                 finish();
47             }
48         });
49
50         builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
51
52             @Override
53             public void onClick(DialogInterface dialog, int which) {
54                 dialog.dismiss();
55             }
56         });
57
58
59         dialog = builder.create();
60     }
61
62     //下面为增加的方法
63     @Override
64     public boolean onKeyDown(int keyCode, KeyEvent event) {
65         // TODO Auto-generated method stub
66         if(keyCode == KeyEvent.KEYCODE_BACK)
67             dialog.show();
68         return super.onKeyDown(keyCode, event);
69     }
70
71 }

上述方法没什么太大的问题。

方法二:Activity中有一个回调方法public void onBackPressed(),从名字可以知道是当按下返回键执行的方法,那么依然需求是当按下返回键就弹出对话框,用户选择是否退出Activity,所以很自然的可以重写这个方法,让Activity被销毁,所以自然而然的有了下面的MainActivity源代码:

 1 package com.my.day22_my_dialog1;
 2
 3 import android.os.Bundle;
 4 import android.view.KeyEvent;
 5 import android.view.View;
 6 import android.view.View.OnClickListener;
 7 import android.widget.Button;
 8 import android.app.Activity;
 9 import android.app.AlertDialog;
10 import android.app.Dialog;
11 import android.content.DialogInterface;
12
13 public class MainActivity extends Activity {
14     private Button bt;
15     private AlertDialog dialog;
16
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21
22         initDialog();
23
24         bt = (Button) findViewById(R.id.bt);
25         bt.setOnClickListener(new OnClickListener() {
26
27             @Override
28             public void onClick(View v) {
29                 dialog.show();
30             }
31         });
32     }
33
34     private void initDialog() {
35         //创建对话框创建器对象
36         AlertDialog.Builder builder = new AlertDialog.Builder(this);
37
38         builder.setTitle("关闭?");
39         builder.setIcon(R.drawable.ic_launcher);
40         builder.setMessage("关闭该Activity?");
41         builder.setCancelable(false);//设置点击对话框之外的内容是否取消对话框
42         builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
43
44             @Override
45             public void onClick(DialogInterface dialog, int which) {
46                 finish();
47             }
48         });
49
50         builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
51
52             @Override
53             public void onClick(DialogInterface dialog, int which) {
54                 dialog.dismiss();
55             }
56         });
57
58
59         dialog = builder.create();
60     }
61
62     //下面为增加的方法
63     @Override
64     public void onBackPressed() {
65         // TODO Auto-generated method stub
66         super.onBackPressed();
67         dialog.show();
68     }
69 }

  然而执行的结果是程序直接崩溃,LogCat捕获的信息如下图:

  以上出错信息第一行可以得到关键信息:***Activity has leaked Window .... (leak:泄露)

  原因是:系统执行onBackPressed()方法后,会继续回调Activity的onPause()、onStop()、onDestroy()等生命周期方法,当最后执行onDestroy()方法会,系统会销毁Activity,而此时Activity界面上显示的对话框依然存在,而对话框依赖的Activity对象已经不存在了,就会出现这种情况应用已经没有了Activity,而这个应用却存在一个对话框,且这个对话框是依赖之前存在的Activity,此时就出现了窗体泄露,程序崩溃。

  在网上搜了很长时间,解决方式是:既然Activity最后肯定会执行onDestroy()方法,那么可以在onDestroy()中强制将对话框关闭,这样就解决了问题。  

  因此第二种方式MainActivity的完整源码:

package com.my.day22_my_dialog1;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;

public class MainActivity extends Activity {
    private Button bt;
    private AlertDialog dialog;

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

        initDialog();

        bt = (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                dialog.show();
            }
        });
    }

    private void initDialog() {
        //创建对话框创建器对象
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        builder.setTitle("关闭?");
        builder.setIcon(R.drawable.ic_launcher);
        builder.setMessage("关闭该Activity?");
        builder.setCancelable(false);//设置点击对话框之外的内容是否取消对话框
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
            }
        });

        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });

        dialog = builder.create();
    }

       //下面为增加的代码
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        if(dialog!=null)
            dialog.dismiss();
        super.onDestroy();

    }
    @Override
    public void onBackPressed() {
        // TODO Auto-generated method stub
        super.onBackPressed();
        dialog.show();
    }
}

  思考:如果采用这种方法,那么在onBackPressed()方法中的方法体不起作用,有没有对话框都无所谓,反正也不起作用,也没有达到需求:“当按下返回键时,出现对话框,选择确定后才会退出当前Activity,该方法只是解决了窗体泄露,而没有解决需求”,因为当你按下返回键,不管你有没有在出现的对话框上操作,系统会自动退出当前Activity。想要想一个办法,重写onBackPressed()等方法,出现对话框,用户做出选择,然后系统才决定是否退出该Activity。

  未完,待续.

时间: 2024-10-05 21:24:10

Android常见问题1:窗体泄露(1)的相关文章

关于android.view.WindowLeaked(窗体泄露)的解决方案

虽然是小问题一个,但也困扰了我一段时间,现在记下来,给自己做个备忘,也可以给其他人一个参考 Java代码   view plaincopy to clipboardprint? 01-08 01:49:27.874: ERROR/WindowManager(473): Activity com.photos.MainActivity has leaked window android.widget.ImageButton@43e40d10 that was originally added he

关于 android.view.WindowLeaked: 窗体泄露

一.问题 E/WindowManager: android.view.WindowLeaked: Activity com.jeany.demo.MainActivity has leaked window [email protected][] that was originally added here at android.view.ViewRootImpl.<init>(ViewRootImpl.java:485) at android.view.WindowManagerGlobal

Android 窗体泄露问题

最近遇到这样一个问题: E/WindowManager(30314): android.view.WindowLeaked: Activity com.xxxxxx.www.activity.XXXActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{52b0f3ac V.E..... R......D 0,0-120,95} that was originally added here

Android postDelay+Dialog引起的窗体泄露

Android中消息队列postDelay+Dialog引起的窗体泄露的主要原因是,当床窗体压入栈或者finish掉后,Activity由于需要处理postDelay而不能及时销毁,因此造成了一个问题,当dialog触发show方法时,由于window和activity已经分开了,因此便会造成窗体泄露. 1.WindowManager$BadTokenException 错误描述:android.view.WindowManager$BadTokenException: Unable to ad

android自定义Activity窗体大小

先给大家看图吧: 看,是不是很酷呢,呵呵. 这里我说关键的地方,就是自定义Activity的窗体大小. 这个登录框它不是一个Dialog,而是一个Activity. 如何定义,即把Activity的主题设置为Theme.Dialog <activity android:name=".AlertDialogActivity"  android:theme="@style/mytheme" /> mytheme.xml是我自定义的主题 mytheme.xml

Android 常见问题收集 (持续更新)

gridview中设置item的高度. 一.BaseAdapter中的getView中设置 AbsListView.LayoutParams param = new AbsListView.LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, parent.getWidth()/2+DpPx.dip2px(context,20));//-20 10spacing 5padding + 40 textview.height

Android常见问题总结(三)

上一篇博客传送门:Android常见问题总结(二) 11. Android的数据存储形式 在Android中的数据存储形式主要有以下几种: SharedPreferrences SharedPreferrences主要用于存储一些少量的简单的应用程序配置信息.SharedPreferrences以明文键值对的形式把数据存储在一个xml文件上,该文件位于/data/data/<package name>/shared_prefs目录下.因此,SharedPreferrences只适合用于存储一些

Cocos2d-x移植Android 常见问题处理办法

1.函数.变量出现"could not be resolved "问题 出现此问题一般是没有找到cocos2d-x声明的头文件,在eclipse将cocos2d的头文件目录引入,包括工程目录.platform/android 在hellocpp/main.cpp函数加入头文件 #include "AppDelegate.h" #include "cocos2d.h" #include "CCEventType.h" #incl

查找并修复Android中的内存泄露—OutOfMemoryError

[编者按]本文作者为来自南非约翰内斯堡的女程序员 Rebecca Franks,Rebecca 热衷于安卓开发,拥有4年安卓应用开发经验.有点完美主义者,喜爱美食. 本文系国内ITOM管理平台 OneAPM 编译呈现,以下为正文. Android 程序中很容易出现内存泄露问题.毫无戒心的开发者可能每天都会造成一些内存泄露,却不自知.你可能从未注意过这类错误,或者甚至都不知道它们的存在.直到你遇到下面这样的异常: java.lang.OutOfMemoryError: Failed to allo