• 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。

      未完,待续.

  • 相关阅读:
    二分图匹配初步
    动态规划初步
    一些排日程的经典方法
    petri网初步
    笔记:美国院士教你写论文
    Ubuntu18.04彻底删除MySQL数据库
    ubuntu18.04 安装 wps2019
    ubuntu18.04 阿里镜像源
    Ubuntu 18.04 使用标准Ubuntu 仓库进行自动化安装NVIDIA驱动
    linux maven环境变量配置
  • 原文地址:https://www.cnblogs.com/enjoy-coding/p/4790144.html
Copyright © 2020-2023  润新知