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

摘要:
8重要应用程序活动;9 importandroid.app.AlertDialog;10importandroid.app.Dialog;20setContentView(R.layout.activity_main);39builder.setIcon(R.drawbable.ic_launcher);

  今天学习对话框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捕获的信息如下图:

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

  以上出错信息第一行可以得到关键信息:***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。

  未完,待续.

免责声明:文章转载自《Android常见问题1:窗体泄露(1)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇百度地图 逆地理编码7th.关于系统时钟的设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

视频编码 率失真性能评价指标:PSNR SSIM BD-rate BD-PSNR

BD-rate 算法 参考 BD-rate,全称Bjøntegaard-Delta rate, 用于评价不同的视频编码器RD(率失真)性能。 写这篇博客,部分原因是发现BD-rate的中文解释完全没有。 算法 1. 一个编码器,给定bitrate,计算PSNR(以Y为例)。取不同的bitrate,在R-D曲线得到四个点。 2. 用三次多项式拟合R-D...

教会你Linux Shell自动交互的三种方法

你了解Linux系统么?你是Linux系统的应用者么?如果你要学习linux,你可能会遇到Linux Shell自动交互问题,这里将介绍Linux Shell自动交互的解决方法,在这里拿出来和大家分享一下。 一、背景 shell脚本在处理自动循环或大的任务方面可节省大量的时间,通过创建一个处理任务的命令清单,使用变量、条件、算术和循环等方法快速创建脚本以完...

网页支付页面代码

<html xmlns:ns1="og" lang="zh" xmlns="http://www.w3.org/1999/xhtml" ns1:xmlns="http://ogp.me/ns#" class=" jsEnabled"><head><meta http-equiv="Content-Type" content="...

微信小程序最新获取用户头像昵称的方法

官方提供的最新方法Open-data标签,使用这个标签可以不用用户授权直接获得头像和昵称 微信小程序获取用户信息的两种方法wx.getUserInfo&open-data https://blog.csdn.net/lucky_Zeng/article/details/80066479...

安卓系统手机目录

一、文件夹 1./acct/    系统回收站,删除的系统文件。     2./cache/    缓存     3./data/    用户的所有程序相关数据     app/    所有用户安装的apk文件     app-private/     data/    每一个应用的数据         com.xx.appname/    每一个应用的数...

php imagemagick 处理 图片剪切、压缩、合并、插入文本、背景色透明

php有一款插件叫做imagemagick,功能很强大,提供了图片的很多操作,图片剪切、压缩、合并、插入文本、背景色透明等。并且有api方法调用和命令行操作两种方式,如果只是简单处理的话建议api方法调用,如果是很复杂的操作建议服务器端搭shell命令行操作,因为api方法调用同操作对比命令行他更吃内存,并且效率没有命令行那么高。 本文章就对于这些常见操作...