未关闭AlertDialog引发的溢出,日期选择对话框

2020-03-14 03:05 来源:未知

现阶段有那般多个供给,从 A activity 跳转到 B activity , 然后在 B activity 分界面中展现叁个 自定义View 的AlertDialog (注意,只是经过setView 方法自定义了view内容,并非自定义控件卡塔尔国,该view包括八个 Button ,二个撤消一个规定,点击裁撤闭馆当前页面并赶回A ;点击明显 关闭当前页面 并跳转到 C activity。

正文转自:

AlertDialog是常事利用控件,前不久本身来剖判一下源码。

接纳日期能够利用DatePicker控件
那是appcompat里的,所以新旧Android系统都可格外

经过设置onClickListener 监听器,当那八个button被点击的时候,先管理局地数据,然后径直调用activity 的finish(卡塔尔 方法关闭当前activity 。然后在运维的时候从不崩溃,不过打字与印刷了一批E大切诺基ROEscort等级的log,内容如下:android.view.WindowLeaked: Activity com.cnpeng.cnpeng_demos2017_01.b_05_alertDialog_dismiss .DissmissAlertDialog has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{1a1d1b07 V.E..... R......D 0,0-684,238} that was originally added here 这段错误的情趣是说:由于Activity在创造以前此中的 有些控件已经存在了(恐怕说是,在 activity 销毁之后它此中的控件还恐怕有没销毁的),所以发生了 窗体溢出。

 

android生手平常会用境遇多少个难点?

<DatePicker
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@ id/dialog_date_date_picker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:calendarViewShown="false"/>

那正是说,故障点在哪呢?经过缜密逐个审查,开掘是出于 三个button是友好加上的,并非调用AlertDialog原有的positiveButton 和 NagetiveButton , 在button的点击事件中调用activity 的 finish 前从未有过止息AlertDialog 。所以,那就招致了activity被消亡之后,AlertDialog 对象还是存在。

摘要: 创立对话框 多少个对话框日常是叁个产出在脚下Activity之上的二个小窗口. 处于下边包车型客车Activity失去主题, 对话框选拔全数的客户交互作用. 对话框日常用于提示消息和与当下应用程序直接有关的小功效.Android API 接济下列项目 ...

  • 窗体溢出的bug;这几个能够参照前边的《android Context 详细明白》。
  • dialog为何只接纳activity的context;那个难点下边就能够得到答案。

而在AlertDialog 提供的PositiveButton 和 NagetiveButton 中已经封装好了 销毁 AlertDialog 的方法 , 所以不需求大家去做拍卖。

创办对话框   二个会话框日常是一个冒出在时下Activity之上的三个小窗口. 处于上边包车型大巴Activity失去核心, 对话框选取全部的顾客人机联作. 对话框日常用于提醒消息和与方今应用程序直接有关的小功效.
  Android API 协助下列项目标对话框对象:
  警示对话框 AlertDialog:  一个足以有0到3个按键, 一个单选框或复选框的列表的对话框. 警报对话框能够创造大许多的相互分界面, 是引用的类型.
  进度对话框 ProgressDialog:  突显三个速度环只怕一个速度条. 由于它是AlertDialog的扩展, 所以它也支撑开关.
  日期选拔对话框 DatePickerDialog:  让客户接受一个日期.
  时间接选举用对话框 提姆ePickerDialog:  让客户筛选三个时间.
  假设您期待自定义你的对话框, 能够扩展Dialog类.
  Showing a Dialog 显示对话框
  叁个会话框总是被成立和展现为多个Activity的一部分. 你应当在Activity的onCreateDialog(int卡塔尔中开创对话框. 当您接收那个回调函数时,Android系统自动处理各类对话框的事态并将它们和Activity连接, 将Activity变为对话框的"全数者". 那样,每一个对话框从Activity世襲部分属性. 比如,当四个对话框张开时, MENU键会显示Activity的菜单, 音量键会调治Activity当前接纳的音频流的音量.
  注意: 倘让你期望在onCreateDialog(卡塔尔(قطر‎方法之外创设对话框, 它将不会依据在Activity上. 你能够选拔setOwnerActivity(Activity卡塔尔(قطر‎来将它依赖在Activity上.
  当您愿意呈现一个对话框时, 调用showDialog(int卡塔尔并将对话框的id传给它.
  当二个会话框第二次被倡议时,Android调用onCreateDialog(int卡塔尔(قطر‎. 这里是你最早化对话框的地点. 那些回调函数字传送入的id和showDialog(int卡塔尔国相符. 创制对话框之后,将重返被成立的对象.
  在对话框被出示早先,Android还有大概会调用onPrepareDialog(int, Dialog卡塔尔. 要是你希望每一趟展现对话框时有动态更正的源委, 那么就改写这么些函数. 该函数在每趟二个会话框张开时都调用. 假使您不定义该函数,则对话框每一回打开都以同出一辙的. 该函数也会流传对话框的id以致你在onCreateDialog(卡塔尔(قطر‎中开创的Dialog对象.
  最棒的定义onCreateDialog(intState of Qatar 和onPrepareDialog(int, Dialog卡塔尔(قطر‎的主意正是利用三个switch语句来检查传入的id. 每一个case创立相应的对话框. 举例, 二个玩耍使用五个对话框: 一个来提示游戏暂停,另叁个提示游戏截止. 首先, 为它们定义ID:static final int DIALOG_PAUSED_ID = 0;
static final int DIALOG_GAMEOVER_ID = 1; 
接下来, 在onCreateDialog(int卡塔尔(قطر‎中走入四个switch语句:

我们深入深入分析了Activity的构造文件加载、绘制流程,算是对总体Android系统中分界面包车型客车展示流程有了叁个光景的垂询,其实Android系统中具有的突显控件(注意这里是控件,实际不是组件)的加载绘制流程都以近乎的,包含:Dialog的加载绘制流程,PopupWindow的加载绘制流程,Toast的体现原理等,上一篇小说中,作者说在介绍了Activity分界面的加载绘制流程之后,就能够分析一下剩余几个控件的来得调节流程,这里小编思虑先深入分析一下Dialog的加载绘制流程。

再把带有那几个空间的构造传给对话框的setView方法
纵使设备旋转客户挑选的日期也不会不改变,因为用构造文件创制datepicker时,编写翻译工具会为它生成唯一id,具备id属性的视图能够保持运市场价格况(?卡塔尔(قطر‎
实质上也得以在代码中创立datepicker,但如此不光想要修正对话框内容时麻烦,还要自行再给datepicker加多id属性

那正是说当 AlertDialog 中的按键被点击之后,如何去销毁AlertDialog呢?其实,也十分轻易,先获得AlertDialog 对象,然后调用其dismiss 方法去销毁。but , 此处一定要静心:在赢得 AlertDialog 对象的时候,不可能动用 create方法去获得,使用该办法获得到的靶子去销毁AlertDialog 时照旧会报溢出!!!必得接收 show 方法获取AlertDialog对象,那样才不会再一次发出溢出。示例代码如下:

view plain

兴许有的同学问这里为何一直不Fragment?其实严峻意义上来说Fragment实际不是三个人展览示控件,而只是一个人展览馆示器件。为啥如此说啊?其实像大家的Activity,Dialog,PopupWindow以至Toast类的此中都管理保证着贰个Window对象,那一个Window对象不仅仅是一个View组件的聚众管理对象,它也促成了组件的加载与绘图流程,而笔者辈的Fragment组件假若看过源码的话,严苛意义上来讲,只是多个View组件的会集併通过调节变量实现了其特定的生命周期,不过其由于并未保卫安全Window类型的分子变量,所以其不抱有组件的加载与绘图效率,因而其不能够独立的被绘制出来,那也是自家把它称为组件并非控件的缘由。(在分析完那多少个控件的加载绘制流程之后,不经常间的话,也会解析一下Fragment的连带源码)


那边只给出 通过setView 生成的 AlertDialog 所在的Activity , 也正是急需中说的 B , A 和 C 中未有至极管理,所以A和C不再给出。

  1. protected Dialog onCreateDialog(int id) {  
  2.     Dialog dialog;  
  3.     switch(id) {  
  4.     case DIALOG_PAUSED_ID:  
  5.         // do the work to define the pause Dialog  
  6.         break;  
  7.     case DIALOG_GAMEOVER_ID:  
  8.         // do the work to define the game over Dialog  
  9.         break;  
  10.     default:  
  11.         dialog = null;  
  12.     }  
  13.     return dialog;  
  14. }   

好啊,起先我们明天有关Dialog的传授,相信我们在通常的付出进度中时时会动用到Dialog弹窗,使用Dialog能够在Activity弹出弹窗,确认音信等。为了更加好的深入分析Dialog的源码,大家那边暂且写三个总结的demo,看一下Dialog的运用实例。

  • 对话框自己是足以自动展现的,但付出FragmentManager管理能够使突显更灵敏
    要成立用来彰显对话框的Fragment类能够让其继承DialogFragment
/** * 作者:CnPeng * <p> * 时间:2017/4/10:下午8:23 * <p> * 说明:自定义AlertDialog的View,点击确定按钮后跳转到下一个页面,并关闭当前页。 * <p> * 需要注意的是,关闭当前页之前需要关闭Alertdialog,否则会导致actvity溢出。溢出的错误信息如下: 并且在关闭dialog的时候,只有通过show() * 方法获取到的dialog对象才可以调用dismiss并实现关闭;用create方法得到的对象则不行 * <p> * 溢出的错误信息如下: android.view.WindowLeaked: Activity com.cnpeng.cnpeng_demos2017_01.b_05_alertDialog_dismiss * .DissmissAlertDialog * has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{1a1d1b07 V.E..... R......D 0,0-684,238} that * was originally added here */public class DissmissAlertDialog extends AppCompatActivity implements View.OnClickListener { private AlertDialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dismiss_alertdialog); Button bt_showDialog =  findViewById(R.id.bt_showAlertDialog); bt_showDialog.setOnClickListener(new View.OnClickListener() { @Override public void onClick { showAlertDialog; } private void showAlertDialog() { AlertDialog.Builder builder = new AlertDialog.Builder; builder.setCancelable; View customDialogView = getLayoutInflater().inflate(R.layout.custom_alertdialog, null); builder.setView(customDialogView); // dialog = builder.create(); //这种还是会报溢出 // builder.show(); dialog = builder.show(); //这样则不会溢出 Button bt_left =  customDialogView.findViewById(R.id.bt_left); Button bt_right =  customDialogView.findViewById(R.id.bt_right); bt_left.setOnClickListener; bt_right.setOnClickListener; } @Override public void onClick { switch ) { case R.id.bt_left: //关闭当前页 if (dialog.isShowing { dialog.dismiss(); } finish(); break; case R.id.bt_right: //关闭当前页面,并跳转到其他页面 CommonUtils.mStartActivity(this, SuspendAndListViewActivity2.class); if (dialog.isShowing { dialog.dismiss(); } finish(); break; } }}

  注意: 在此个事例中, case语句为空因为定义Dialog的顺序在后面会有介绍.
  在须求体现对话框是, 调用showDialog(int卡塔尔(قطر‎, 传入对话框的id:
  showDialog(DIALOG_PAUSED_IDState of Qatar;Dismissing a Dialog 驱除对话框
  当您希图关门对话框时, 你能够动用dismiss(卡塔尔(قطر‎函数. 假如需求的话, 你也能够从Activity调用dismissDialog(int卡塔尔(قطر‎, 二者效果是一律的.
  假如你利用onCreateDialog(int卡塔尔来治本你的对话框的情况, 那么每趟你的对话框被消除时, 该对话框对象的境况会被Activity保存. 假设你说了算你不再供给以此目的或许须要免去对话框的场馆, 那么你应当调用 removeDialog(int卡塔尔. 那将把具有该目的的中间援引移除, 假诺该对话框在展现的话将被衰亡.
  Using dismiss listeners 使用消灭监听器
  假设你期望在对话框祛除时运维某个程序, 那么你应有给对话框附加三个消弭监听器.
  首先定义DialogInterface.OnDismissListener接口. 那一个接口唯有一个办法, onDismiss(DialogInterfaceState of Qatar, 该方式将要对话框肃清时被调用.
  然后将您的OnDismissListener完毕传给setOnDismissListener(卡塔尔(قطر‎.
  然则,注意对话框也能够被"撤除". 那是二个别具一格之处, 它意味着对话框被客商显式的吊销掉. 那将要客商按下"back"键时, 只怕对话框显式的调用cancel(卡塔尔(按下对话框的cancel开关卡塔尔国时产生. 当一个会话框被注销时, OnDismissListener将一直以来被打招呼, 但就算您希望在对话框被展现裁撤(并非例行打消卡塔尔时被通报, 则你应有运用setOnCancelListener(卡塔尔注册三个DialogInterface.OnCancelListener.
  Creating an AlertDialog 创立警告对话框
  An AlertDialog is an extension of the Dialog class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. You should use it for dialogs that use any of the following features:
  二个告诫对话框是对话框的一个恢宏. 它亦可创制大相当多会话框顾客界面并且是推荐的对话框类新星. 对于急需下列任何天性的对话框,你都应有运用它:
  八个题名
  一条文字音信
  1个-3个按钮
  叁个可选取的列表(单选框大概复选框卡塔尔国
  要创立多个AlertDialog, 使用AlertDialog.Builder子类. 使用AlertDialog.Builder(Context卡塔尔(قطر‎来博取多个Builder, 然后接纳该类的公有方法来定义AlertDialog的属性. 设定好未来, 使用create(卡塔尔国方法来获得AlertDialog对象.
  上面包车型客车核心显得了什么样为AlertDialog定义分歧的天性, 使用AlertDialog.Builder类. 假如您接受那么些示例代码, 你能够在onCreateDialog(State of Qatar中回到最后的Dialog对象来获得图片中对话框的效果.
  Adding buttons 扩大开关

title.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setIcon(R.mipmap.ic_launcher);
                builder.setMessage("this is the content view!!!");
                builder.setTitle("this is the title view!!!");
                builder.setView(R.layout.activity_second);
                builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss();
                    }
                });
                alertDialog = builder.create();
                alertDialog.show();
            }
        });

本例中成立DatePickerFragment容纳日历空间供顾客筛选日期,要贯彻一打开对话框呈现原日期,将要在开发对话框时传入参数

AlertDialog的view。

图片 1

咱俩在Activity中取得叁个textView组件,并监听TextView的点击事件,并在点击事件中,初叶化一个AlertDialog弹窗,并试行AlertDialog的show方法体现弹窗,在弹窗中定义一个按键,并监听弹窗开关的点击事件,若客户点击了弹窗的开关,则实践AlertDialog的dismiss方法,废除体现AlertDialog。

public static DatePickerFragment newInstance(Date date)
{
        Bundle bundle=new Bundle();
        bundle.putSerializable(ARG_DATE,date);
        DatePickerFragment datePickerFragment=new DatePickerFragment();
        datePickerFragment.setArguments(bundle);
        return datePickerFragment;
}
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:andro android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="@dimen/dp10" android:text="随便写的一个布局界面"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android: android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="左侧按钮"/> <Button android: android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="右侧按钮"/> </LinearLayout></LinearLayout>

要开创叁个如图所示的窗口, 使用set...Button(卡塔尔(قطر‎方法:

能够见到大家定义的icon,title,message和button都曾经显示出来了,此时大家点击弹窗按键知道了,那个时候弹窗就能够收敛了。


  • 、AlertDialog 中提供的 positiveButton 和 Nagetivebutton内部已经贯彻了 销毁 AlertDialog 的 dismiss 方法,所以在调用那多少个开关的时候,无需手动 dismiss
  • 、本人写的 button 中 须要手动创制 AlertDialog 对象去调用 dismiss 方法进而销毁 AlertDialog。可是,创设AlertDialog对象的时候须求利用 show 方法成立,而不可能用 create 创设
  • 、想不驾驭啊,为何用 create 方法创造的 对象达不到销毁的指标呢??其实查看 show 内部也是调用 create 创制对象并重回。。。真是没想精通。

view plain

平日大家应用Dialog的光景流程都是那般的,恐怕定制Dialog的时候有部分定制化的操作,可是基本操作流程依旧这样的。

内需实现DialogFragment的onCreateDialog方法,在个中间成立对话框

代码地址: 对应内部 的 b_05.

  1. AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  2. builder.setMessage("Are you sure you want to exit?")  
  3.        .setCancelable(false)  
  4.        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {  
  5.            public void onClick(DialogInterface dialog, int id) {  
  6.                 MyActivity.this.finish();  
  7.            }  
  8.        })  
  9.        .setNegativeButton("No", new DialogInterface.OnClickListener() {  
  10.            public void onClick(DialogInterface dialog, int id) {  
  11.                 dialog.cancel();  
  12.            }  
  13.        });  
  14. AlertDialog alert = builder.create();  

那么大家先来看一下AlertDialog.Builder的布局方法,这里的Builder是AlertDialog的中间类,用于封装AlertDialog的组织进度,看一下Builder的构造方法:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState){
Date date=(Date)getArguments().getSerializable(ARG_DATE);

基本上快贰个半月没写东西了,为何呢?忙吗?其实也不忙;不忙吗?其实每一周都有新须要,都有各个急需改的bug。

到底,其实是那一个多月变的懒了,书也读的少了,代码也敲的少了。年底的时候,给和煦的靶子是把手上关于安卓和java的四本书通读二遍同临时候把里面包车型客车享有代码都敲二遍,不过,以后17年都过去六成了,小编的书才读了一本中的四成,离目的还差的好远好远。。。现在的意况的确不佳,还是赶紧改换吗。

先是,使用setMessage(CharSequence卡塔尔(قطر‎为对话框扩充一条信息。 然后, 伊始接二连三调用方法, 使用setCancelable(booleanState of Qatar将对话框设为不可撤废(无法动用back键来废除)。对每八个按键,使用set...Button(State of Qatar方法,该方法接纳开关名称和叁个DialogInterface.OnClickListener,该监听器定义了当顾客选用该按键时应做的动作。
  注意:对每一个按键类型,只可以为AlertDialog成立一个。也正是说,二个AlertDialog无法有多少个以上的"positive"开关。这使得恐怕的按键数量最多为八个:显著、否定、中性。那些名字和实际职能还没关联,但是将救助你记得它们各做哪些业务。

public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }
    //Date对象是一个时间戳,无法直接提供整数形式的年月日
    //要先创建一个Calendar对象然后用date来配置它,再从其中取出年月日
    Calendar calendar=Calendar.getInstance();
    calendar.setTime(date);
    int year=calendar.get(Calendar.YEAR);
    final int month=calendar.get(Calendar.MONTH);
    int day=calendar.get(Calendar.DAY_OF_MONTH);

    //获得对话框内容的布局
    View v= LayoutInflater.from(getActivity())
        .inflate(R.layout.dialog_date,null);

    mDatePicker=(DatePicker)v.findViewById(R.id.dialog_date_date_picker);
    //设定日历值为当前记录
    mDatePicker.init(year,month,day,null);

    return new AlertDialog.Builder(getActivity())
            .setView(v)
            .setTitle(R.string.date_picker_title)
            .setPositiveButton(android.R.string.ok,null)
                                    .create();
}

Adding a list 扩展列表

此地调用的是Builder的重载布局方法:


图片 2

public Builder(Context context, int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));
        }

对话框是AlertDialog类的实例,AlertDialog是个常用的多用场Dialog子类
AppCompat宽容库能将一部分新型系统的性状效果与利益移植到Android的旧版本上
提出将AlertDialog封装在DialogFragment中,使用FragmentManager管理对话框会越来越灵敏
若设备旋转,单独行使的AlertDialog会收敛,而封装在fragment中的旋转后会被重新建立
动用AlertDialog.Builder类,给其布局方法传入Context,再次来到多个AlertDialog实例,调用该实例的以下方法
setTitle(int titleId)
setView(View v)
安装对话框的展示内容
setPositiveButton(int textId,DialogInterface.onClickListener listener)
其次个参数是落到实处DialogInterface.OnClickListener接口的对象(监听器)
三种对话框按键:positive,negative,neutral卡塔尔国
create()

要创造三个富有可筛选的AlertDialog,使用setItems(State of Qatar方法:

那正是说这里的P是AlertDialog.Builder中的一个AlertController.AlertParams类型的分子变量,可知在此进行了P的初阶化操作。


view plain

public AlertParams(Context context) {
            mContext = context;
            mCancelable = true;
            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

创建DatePickerFragment对象,
累积给FragmentManager并内置荧屏上(CrimeFragment的开关点击事件里)
DialogFragment也交由CrimeActivity托管

  1. final CharSequence[] items = {"Red", "Green", "Blue"};   
  2. AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  3. builder.setTitle("Pick a color");  
  4. builder.setItems(items, new DialogInterface.OnClickListener() {  
  5.     public void onClick(DialogInterface dialog, int item) {  
  6.         Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();  
  7.     }  
  8. });  
  9. AlertDialog alert = builder.create();  

能够看出此间根本实行了AlertController.AlertParams的开头化操作,伊始化了一些成员变量。那样进行了一多重操作之后我们的代码:

FragmentManager manager=getFragmentManager();
DatePickerFragment dialog=DatePickerFragment.newInstance(mCrime.getDate());
dialog.show(manager,DIALOG_DATE);

先是扩张二个题名。然后接受setItems(卡塔尔国增添贰个可选列表,该列表接纳三个精选名称的列表和一个DialogInterface.OnClickListener, 前者定义了选拔对应的响应。

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

二种办法:
1.体系活动创制并付出业务
public void show(FragmentManager,String Tag)
2.自动创制并提交业务
public void show(FragmentTransaction transaction, String tag)
tag作为fragment在FragmentManager里的独一标记

Adding checkboxes and radio buttons 增添单选框和复选框

就曾经实施到位了,然后大家调用了builder.setIcon方法,这里看一下setIcon方法的实际贯彻:


 图片 3

public Builder setIcon(@DrawableRes int iconId) {
            P.mIconId = iconId;
            return this;
        }

由来学到的三种展现fragment的艺术
1.常备的创设,然后普通的利用FragmentManager提交事务
2.ViewPager中运用FragmentStatePagerAdapter代理实现创制与作业提交
3.DialogFragment.show()

要开创三个蕴涵多选列表大概单选列表的对话框, 使用setMultiChoiceItems(卡塔尔(قطر‎和setSingleChoiceItems(State of Qatar方法。假若你在onCreateDialog(卡塔尔中创立可选择列表, Android会自动管理列表的状态. 只要activity依旧活跃, 那么对话框就会铭记刚才选中的选项,但当客户退出activity时,该选取错过。
  注意: 要在您的acitivity离开和间断时保留采纳, 你不得不在activity的扬言周期中国科高校学的保留和恢复设置。为了永世性保存选取,你不得不接收数据存款和储蓄技能中的一种。
  要创立多少个存有单选列表的AlertDialog,只需将三个事例中的setItems(State of Qatar换成setSingleChoiceItems(State of Qatar:

能够看看AlertDialog的Builder的setIcon方法,这里举办的正是给项目为AlertController.AlertParams的P的mIconId赋值为传送的iconId,并且那几个措施重临的花色正是Builder。


view plain

接下来我们调用了builder.setMessage方法,能够看一下builder.setMessage方法的切实完结:

再对话框中挑选了日期再次来到CrimeFragment时要把数量传回到
那是七个被同七个Activity托管的Fragment间的数据沟通

  1. final CharSequence[] items = {"Red", "Green", "Blue"};   
  2. AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  3. builder.setTitle("Pick a color");  
  4. builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {  
  5.     public void onClick(DialogInterface dialog, int item) {  
  6.         Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();  
  7.     }  
  8. });  
  9. AlertDialog alert = builder.create();  
public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

得以完成activity的数码回传,是经过ActivityManager肩负追踪管理父activity和子activity间的关系。
回传数据后子activity被销毁,但ActivityManager知道选择数据的是哪个activity
类比那个,能够将CrimeFragment作为DatePickerFragment回传数据的目标Fragment,纵然CrimeFragment与DatePickerFragment被销毁和重新建立后,操作系统也会再次关联它们

其次个参数是私下认可被入选的选项地点,使用“-1”来代表暗许情形下不选中任何选项。

好呢,这里跟setIcon方法的落到实处逻辑相符,都以给成员变量的mMessage赋值为大家传递的Message值,且和setIcon方法形似的,这几个主意重临值也是Builder。

//CrimeFragment中创建dialog时
FragmentManager manager=getFragmentManager();
DatePickerFragment dialog=DatePickerFragment.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this,REQUEST_DATE);
dialog.show(manager,DIALOG_DATE);

dialog.setTargetFragment(CrimeFragment.this,REQUEST_DATE);

Creating a ProgressDialog 创立进程对话框

再看一下builder.setTitle方法:

在DatePickerFragment中能够通过getTargetFragment(卡塔尔和getTargetRequestCode(卡塔尔国来收获那七个参数
对象fragment和须求代码由FragmentManager担负追踪管理

图片 4

public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }

三个ProgressDialog(进程对话框卡塔尔是AlertDialog的扩大。它能够显得多个速度的动漫――进程环恐怕进度条。那一个对话框也得以提供开关,譬如裁撤叁个下载等。
  展开叁个速度对话框比较轻松,只供给调用 ProgressDialog.show(State of Qatar就能够。例如,上海教室的对话框能够不通过onCreateDialog(int卡塔尔,而直接显示:
  ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "",
  "Loading. Please wait...", true);
  第三个参数是应用程序上下文。第叁个为对话框的标题(这里为空),第七个为对话框内容, 最后叁个为该进程是或不是为不可明确的(那只跟进度条的开创有关,见下一节)。
  进程对话框的暗许样式为二个筋斗的环。假若你希望呈现速度值,请看下一节。
  Showing a progress bar 显示进程条
  使用三个动画片进程条来显示速度:
  使用 ProgressDialog(Context卡塔尔布局函数来初始化多个ProgressDialog对象。
  将进程样式设置为"STYLE_HOEscortIZONTAL",使用setProgressStyle(int卡塔尔方法。何况安装任何性质,举例内容等。
  在急需体现时调用show(卡塔尔大概从onCreateDialog(int卡塔尔回调函数中回到该ProgressDialog。
  你能够利用 setProgress(int卡塔尔(قطر‎恐怕incrementProgressBy(int卡塔尔国来充实展现的速度。
  举例,你的设置只怕像这么:ProgressDialog progressDialog;
progressDialog = new ProgressDialog(mContext);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
  设置很粗大略。超越55%成立进度对话框需求的代码是在创新它的进度中。你可能必要在三个新的线程中立异它,并选择Handler来将进程报告给Activity。假让你面生使用Handler和别的的线程,请看下列例子,该例子使用了叁个新的线程来更新速度。
  Example ProgressDialog with a second thread 例--使用一个线程来展现速度对话框
  这么些例子使用一个线程来跟踪二个进程的速度(其实为从1数到100)。每当进度更新时,该线程通过Handler给主activity发送八个信息。主Activity更新ProgressDialog.package com.example.progressdialog;

能够开采builder的setIcon、setMessage、setTitle等艺术都是给Builder的分子变量P的icon,message,title赋值。

从子activity退回到父activity时,父activity选取到调用Activity.onActivityResult方法的下令,其FragmentManager会调用对应fragment的onActivityRequestCode(State of Qatar
那下不是从activity退回activity,是从fragment退回fragment,就平昔不地点哪个机制,所以采纳在DatePickerFragment里活动调用CrimeFragment的onActivityTiggosetult

view plain

下一场我们看一下builder.setView方法:

private void sendResult(int resultCode,Date date){
        if(getTargetFragment()==null)
            return;
        Intent intent=new Intent();
        intent.putExtra(EXTRA_DATE,date);

        getTargetFragment().onActivityResult(getTargetRequestCode(),resultCode,intent);
    }
  1. import android.app.Activity;  
  2. import android.app.Dialog;  
  3. import android.app.ProgressDialog;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.widget.Button;  
  10. public class NotificationTest extends Activity {  
  11.     static final int PROGRESS_DIALOG = 0;  
  12.     Button button;  
  13.     ProgressThread progressThread;  
  14.     ProgressDialog progressDialog;  
  15.     /** Called when the activity is first created. */  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);   
  19.         // Setup the button that starts the progress dialog  
  20.         button = (Button) findViewById(R.id.progressDialog);  
  21.         button.setOnClickListener(new OnClickListener(){  
  22.             public void onClick(View v) {  
  23.                 showDialog(PROGRESS_DIALOG);  
  24.             }  
  25.         });  
  26.     }  
  27.     protected Dialog onCreateDialog(int id) {  
  28.         switch(id) {  
  29.         case PROGRESS_DIALOG:  
  30.             progressDialog = new ProgressDialog(NotificationTest.this);  
  31.             progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
  32.             progressDialog.setMessage("Loading...");  
  33.             progressThread = new ProgressThread(handler);  
  34.             progressThread.start();  
  35.             return progressDialog;  
  36.         default:  
  37.             return null;  
  38.         }  
  39.     }   
  40.     // Define the Handler that receives messages from the thread and update the progress  
  41.     final Handler handler = new Handler() {  
  42.         public void handleMessage(Message msg) {  
  43.             int total = msg.getData().getInt("total");  
  44.             progressDialog.setProgress(total);  
  45.             if (total >= 100){  
  46.                 dismissDialog(PROGRESS_DIALOG);  
  47.                 progressThread.setState(ProgressThread.STATE_DONE);  
  48.             }  
  49.         }  
  50.     };   
  51.     /** Nested class that performs progress calculations (counting) */  
  52.     private class ProgressThread extends Thread {  
  53.         Handler mHandler;  
  54.         final static int STATE_DONE = 0;  
  55.         final static int STATE_RUNNING = 1;  
  56.         int mState;  
  57.         int total;  
  58.         ProgressThread(Handler h) {  
  59.             mHandler = h;  
  60.         }  
  61.         public void run() {  
  62.             mState = STATE_RUNNING;     
  63.             total = 0;  
  64.             while (mState == STATE_RUNNING) {  
  65.                 try {  
  66.                     Thread.sleep(100);  
  67.                 } catch (InterruptedException e) {  
  68.                     Log.e("ERROR", "Thread Interrupted");  
  69.                 }  
  70.                 Message msg = mHandler.obtainMessage();  
  71.                 Bundle b = new Bundle();  
  72.                 b.putInt("total", total);  
  73.                 msg.setData(b);  
  74.                 mHandler.sendMessage(msg);  
  75.                 total ;  
  76.             }  
  77.         }  
  78.         /* sets the current state for the thread, 
  79.          * used to stop the thread */  
  80.         public void setState(int state) {  
  81.             mState = state;  
  82.         }  
  83.     }  
  84. }  
public Builder setView(int layoutResId) {
            P.mView = null;
            P.mViewLayoutResId = layoutResId;
            P.mViewSpacingSpecified = false;
            return this;
        }

重写对话框positive开关监听器的代码
并在此面赢得顾客设定的日期值,并调用sendResult将值重返给CrimeFragment

Creating a Custom Dialog 成立自定义对话框

可以窥见此处的setView和setIcon,setMessage,setTitle等办法都以临近的,都以将大家传递的数据值赋值给Builder的分子变量P。

.setPositiveButton(android.R.string.ok,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                int year=mDatePicker.getYear();
                                int month=mDatePicker.getMonth();
                                int day=mDatePicker.getDayOfMonth();
                                Date date=new GregorianCalendar(year,month,day).getTime();
                                sendResult(Activity.RESULT_OK,date);
                            }
                        })

图片 5

下一场我们调用了builder.setPositiveButton方法:

实现Crime Fragment的onActivityResult
抽取回传的数码

设若你想自定义三个会话框,你能够接纳布局成分来创建你的对话框的构造。定义好构造后,将根View对象或许布局财富ID传给setContentView(View卡塔尔.
比如说,创设如图所示的对话框:
创设一个xml布局custom_dialog.xml:

builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss();
                    }
                });
@Override
    public void onActivityResult(int requestCode,int resultCode,Intent intent){

        if(resultCode!=Activity.RESULT_OK)
            return;
        if(requestCode==REQUEST_DATE){
            Date date=(Date)intent.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
            mCrime.setDate(date);

            updateDate();
        }
    }

view plain

此地我们看一下builder的setPositiveButton的源码:

  1. "  
  2.               android:id="@ id/layout_root"  
  3.               android:orientation="horizontal"  
  4.               android:layout_width="fill_parent"  
  5.               android:layout_height="fill_parent"  
  6.               android:padding="10dp"  
  7.               >  
  8.                    android:layout_width="wrap_content"  
  9.                android:layout_height="fill_parent"  
  10.                android:layout_marginRight="10dp"  
  11.                />  
  12.                   android:layout_width="wrap_content"  
  13.               android:layout_height="fill_parent"  
  14.               android:textColor="#FFF"  
  15.               />  
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
            P.mPositiveButtonText = text;
            P.mPositiveButtonListener = listener;
            return this;
        }

该xml定义了叁个LinearLayout中的八个ImageView 和二个TextView。
将上述布局划虚构为对话框的content view,况兼定义ImageView 和 TextView的开始和结果:

行吗,能够开掘跟上边多少个点子依旧相通的,皆感到Builder的分子变量P的对应成员变量赋值。。。

view plain

地方运用的链式编制程序,不止代码轻便并且清晰,通常得以多应用这种办法。

  1. Context mContext = getApplicationContext();  
  2. Dialog dialog = new Dialog(mContext);   
  3. dialog.setContentView(R.layout.custom_dialog);  
  4. dialog.setTitle("Custom Dialog");  
  5. TextView text = (TextView) dialog.findViewById(R.id.text);  
  6. text.setText("Hello, this is a custom dialog!");  
  7. ImageView image = (ImageView) dialog.findViewById(R.id.image);  
  8. image.setImageResource(R.drawable.android);  

下一场大家调用了builder.create方法,而且那么些点子再次回到了AlertDialog。

在起头化Dialog从此未来,使用setContentView(int卡塔尔(قطر‎,将结构财富id传给它。今后Dialog有三个概念好的构造,你能够应用findViewById(int卡塔尔来找到该因素的id并修正它的内容。
  使用后边所讲的艺术突显对话框。
  二个施用Dialog类创立的对话框必得有八个标题。若是您不调用setTitle(State of Qatar,那么标题区域会保留空白。若是你不指望有二个题名,那么您应有运用AlertDialog类来成立自定义对话框。但是,由于二个AlertDialog使用AlertDialog.Builder类来树立最有利,所以你从未办法应用setContentView(int卡塔尔(قطر‎,而是只好利用setView(ViewState of Qatar。该办法选用一个View对象,所以你供给从xml中张开你的根View。
  要扩充一个xml构造,使用 getLayoutInflater(卡塔尔(قطر‎ (或 getSystemService(卡塔尔卡塔尔(قطر‎得到LayoutInflater,然后调用inflate(int, ViewGroup卡塔尔,第2个参数为布局id,而第二个参数为根view的id。未来,你可以运用举办后的结构来找到View对象并定义ImageView和TextView成分的剧情。然后实例化AlertDialog.Builder并动用setView(View卡塔尔来为对话框设置开展后的布局。举个例子:

public AlertDialog create() {
            // Context has already been wrapped with the appropriate theme.
            final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

view plain

能够看看此间首先构造了叁个AlertDialog,大家能够看一下以此构造方法的切实贯彻:

  1. AlertDialog.Builder builder;  
  2. AlertDialog alertDialog;   
  3. Context mContext = getApplicationContext();  
  4. LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);  
  5. View layout = inflater.inflate(R.layout.custom_dialog,  
  6.                                (ViewGroup) findViewById(R.id.layout_root));  
  7. TextView text = (TextView) layout.findViewById(R.id.text);  
  8. text.setText("Hello, this is a custom dialog!");  
  9. ImageView image = (ImageView) layout.findViewById(R.id.image);  
  10. image.setImageResource(R.drawable.android);  
  11. builder = new AlertDialog.Builder(mContext);  
  12. builder.setView(layout);  
  13. alertDialog = builder.create();  
AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
                createContextThemeWrapper);

        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = new AlertController(getContext(), this, getWindow());
    }

采取AlertDialog来自定义对话框,可以运用其置于个性举例按键、接受列表、标题、Logo等。

能够看来这里首先调用了super的构造方法,而笔者辈的AlertDialog世袭于Dialog,所以这里实行的正是Dialog的结构方法,行吗,继续看一下Dialog的布局方法:

来得对话框

    对话框平日作为Activity的一有的来创立和出示。你平常应该从protected Dialog Activity.onCreateDialog (int id) 回调方法里创设对话框。当你接受这么些回调函数时,Android系统会使得的安装那几个Activity为种种对话框的全部者,进而自动管理每种对话框的场所并挂靠到Activity上。那样,每一个对话框继承那些Activity的一定属性。举个例子,当贰个对话框展开时,菜单键突显为那些Activity定义的选项菜单,音量键改进Activity使用的音频流。

  1. 静心: 假设您决定在onCreateDialog(卡塔尔国方法之外创建一个会话框,它将不会被附着到运动上。不过,你能够经过setOwnerActivity(Activity卡塔尔(قطر‎把它附着到二个活动上。 

    当你想要突显八个会话框时,调用showDialog(int id卡塔尔(قطر‎ 方法并传递四个独一标记那些对话框的整数。

    当对话框第三遍被倡议时,Android从你的Activity中调用onCreateDialog(int id卡塔尔,你应当在那间初阶化那一个对话框Dialog。这些回调方法被传以和showDialog(int id卡塔尔(قطر‎肖似的ID。当您成立这一个对话框后,在Activity的结尾回来这一个指标。

    在对话框被出示从前,Android还调用了可选的回调函数onPrepareDialog(int id, DialogState of Qatar. 若是你想在每叁遍对话框被展开时改造它的别的性质,你能够定义那一个措施。这些方式在历次打开对话框时被调用,而onCreateDialog(intState of Qatar仅在对话框第叁回张开时被调用。倘使您不定义onPrepareDialog(State of Qatar,那么这些对话框将保持和上次开采时相仿。这几个措施也被传送以对话框的ID,和在onCreateDialog(卡塔尔(قطر‎中开创的对话框对象。(个人明白是,在本Activity里第叁遍show某些Dialog,则先调用onCreateDialog,得到重返的Dialog对象并挂靠在Activity,保存Dialog对象的援引,然后才彰显Dialog。那样子,下一次再show Dialog就不要再行创造Dialog对象,而是录取旧的卡塔尔(قطر‎

    定义onCreateDialog(int) 和 onPrepareDialog(int, Dialog) 回调函数的精品格局是利用叁个switch 语句来检查传递步向的id 参数。每一种case 应该检查三个独一的对话框ID然后创造和定义相应的对话框。譬如,想象一下两个嬉戏选拔多少个不等的对话框:八个用来提示这些娱乐已经暂停而另二个来提示游戏停止。首先,为每一个对话框定义二个常量:

  1. static final int DIALOG_PAUSED_ID = 0; 
  2. static final int DIALOG_GAMEOVER_ID = 1; 

然后,为每一个ID用一个switch case定义那一个onCreateDialog(int卡塔尔 回调函数:

  1. protected Dialog onCreateDialog(int id) { 
  2.     Dialog dialog; 
  3.     switch(id) { 
  4.     case DIALOG_PAUSED_ID: 
  5.         // do the work to define the pause Dialog 
  6.         break; 
  7.     case DIALOG_GAMEOVER_ID: 
  8.         // do the work to define the game over Dialog 
  9.         break; 
  10.     default: 
  11.         dialog = null; 
  12.     } 
  13.     return dialog; 

当是时候显得中间之一的对话框时,使用对话框ID调用showDialog(int卡塔尔(قطر‎:

  1. showDialog(DIALOG_PAUSED_ID); 

 

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == 0) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }

排除对话框Dismissing a Dialog

    当您计划关门对话框时,你能够透过对那几个对话框调用dismiss()来清除它。要是须求,你还足以从这一个Activity中调用dismissDialog(int idState of Qatar 方法,那实际将为你对这些对话框调用dismiss(卡塔尔国 方法。

    如若你想使用onCreateDialog(int id卡塔尔(قطر‎ 方法来保管你对话框的状态(就好像同在前边的章节斟酌的那样),然后每一趟你的对话框祛除的时候,那一个对话框对象之处将由该Activity保留。假若你调整不再需求以此目的只怕消亡本场所是首要的,那么你应该调用removeDialog(int id卡塔尔(قطر‎。那将去除任何内部对象援引並且只要这几个对话框正在呈现,它将被肃清。

 

能够发未来Dialog的构造方法中央机关单位接直接协会了二个PhoneWindow,并赋值给Dialog的积极分子变量mWindow,从这里能够见到其实Dialog和Activity的显得逻辑都以相像的,都是透过相应的Window变量来兑现窗口的加载与呈现的。然后大家实践了有的Window对象的初步化操作,比方设置回调函数为自个儿,然后调用了Window类的setWindowManager方法,并传到了WindowManager,能够开掘这里的WindowManager对象是透过艺术:

选拔覆灭侦听器Using dismiss listeners

    即便你指望你的应用程序在一个对话框衰亡的时候实行一些流程,那么你应当附着三个on-dismiss侦听器到对话框上。

  1. @Override 
  2. protected void onPrepareDialog(int id, Dialog dialog) { 
  3.     switch(id){ 
  4.     case PROGRESS_DIALOG: 
  5.         dialog.setOnDismissListener(new DialogInterface.OnDismissListener(){ 
  6.             @Override 
  7.             public void onDismiss(DialogInterface dialog) { 
  8.                 Toast.makeText(getApplicationContext(), 
  9.                         "dismiss listener!", 
  10.                         Toast.LENGTH_SHORT) 
  11.                 .show(); 
  12.             } 
  13.         }); 
  14.     } 

    可是, 请注意对话框也能够被“撤废”。那是四个标记对话框被顾客显示打消的不一样通常处境。那将在客商按“重返”按钮时发生,可能那些对话框突显的调用cancel(卡塔尔国 (或许通过对话框上的多个“打消”开关)。当八个会话框被注销时,这些OnDismissListener 依旧会被通报到,可是如若您愿目的在于对话框被展现撤废时被打招呼到(实际不是司空眼惯的消弭形式),那么您应当通过setOnCancelListener(卡塔尔(قطر‎注册多少个DialogInterface.OnCancelListener 。

    近日个人学习意识,经常景观下,调用dialog.cancel(卡塔尔就能够触发onCancelLister。而点击AlertDialog的NegativeButton (Cancel/No卡塔尔(قطر‎是不会触发的。对于setOnCancelListener(卡塔尔国要留神的是,这里有多少个setOnCancelListener(卡塔尔(قطر‎,但再次来到值分化:

  1. //AlertDialog.Builder调用的 
  2. public AlertDialog.Builder setOnCancelListener (DialogInterface.OnCancelListener onCancelListener) 
  3.  
  4. //Dialog调用的 
  5. public void setOnCancelListener (DialogInterface.OnCancelListener listener) 

 

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

告诫对话框AlertDialog的施用

    为了创建四个警戒对话框,使用AlertDialog.Builder 子类。通过AlertDialog.Builder(Context卡塔尔获取叁个布局器然后接受这么些类的集体艺术来定义务警察报对话框的有所属性。当得到布局器后,通过create(State of Qatar.方法来获取警示对话框对象。有的时候本人是不调用create(State of Qatar的,而是在设置好了后一贯调用show(卡塔尔(قطر‎展现AlertDialog。

图片 6 图片 7 图片 8

收获的,而作者辈的context传入的是Activity对象,所以这里的WindowManager对象实际和Activity获取的WindowManager对象是平等的。然后大家看一下window类的setWindowManager方法:

追加开关Adding buttons

    那正是作者一开头很想掌握的究竟如何增加Yes/No,Ok/Cancel这样的开关。原本是经过setPositiveButton(...卡塔尔国响应Yes/Ok的点击,setNeutralButton(...卡塔尔国响应中立行为的点击,setNegativeButton(...卡塔尔响应No/Cancel的点击。注意,只可以分别设置叁个开关来响应点击事件。

  1. AlertDialog.Builder builder = new AlertDialog.Builder(this); 
  2. builder.setMessage("Are you sure you want to exit?") 
  3.        .setCancelable(false) 
  4.        .setPositiveButton("Yes", new DialogInterface.OnClickListener() { 
  5.            public void onClick(DialogInterface dialog, int id) { 
  6.                 MyActivity.this.finish(); 
  7.            } 
  8.        }) 
  9.        .setNegativeButton("No", new DialogInterface.OnClickListener() { 
  10.            public void onClick(DialogInterface dialog, int id) { 
  11.                 dialog.cancel(); 
  12.            } 
  13.        }); 
  14. AlertDialog alert = builder.create(); 

    首先,为那个对话框增添三个信息setMessage(CharSequence卡塔尔(قطر‎。然后,初始函数链并安装该对话框为无法撤除not cancelable (由此顾客不能够应用再次来到开关关闭这几个对话框)。对各样开关,使用任一set...Button(卡塔尔方法,举例setPositiveButton(卡塔尔国,该方式选择按键名称以致叁个定义顾客选中开关后所应用动作的DialogInterface.OnClickListener。

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
扩大五个列表Adding a list
  1. final CharSequence[] items = {"Red", "Green", "Blue"}; 
  2.   
  3. AlertDialog.Builder builder = new AlertDialog.Builder(this); 
  4. builder.setTitle("Pick a color"); 
  5. builder.setItems(items, new DialogInterface.OnClickListener() { 
  6.     public void onClick(DialogInterface dialog, int item) { 
  7.         Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); 
  8.     } 
  9. }); 
  10. AlertDialog alert = builder.create(); 

    首先,用setTitle(CharSequence卡塔尔(قطر‎方法给对话框加多多少个标题。然后,增添用setItems(卡塔尔国增多多个可选项列表,该列表选拔一组突显的items和叁个DialogInterface.OnClickListener 来定义客户选中按钮后所运用动作。

能够见到跟Activity的Window对象的windowManager的获取方式是同样的,都以通过new的不二等秘书籍开创叁个新的WindowManagerImpl对象。好呢,继续回到大家的AlertDialog的布局方法中,在布局方法中,大家除了调用Dialog的布局方法之外还实践了:

追加复选框和单选开关

    要在对话框里成立叁个多选项列表(checkboxes)可能单选项(radio buttons),可各自调用setMultiChoiceItems(卡塔尔 和setSingleChoiceItems(State of Qatar 方法。假如你在onCreateDialog(卡塔尔(قطر‎回调函数中成立这一个可选列表,Android会帮你处理列表状态。只要那么些活动是激活的,对话框会记住此前入选的items,但假如客商退出这一个运动,顾客接收将错过。

    注意: 为了在客户间距或暂停那些运动的时候可以保留选用,你必须要经过运动生命期Activity Lifecycle来方便的保存和苏醒设置。为了长久保存选项,固然活动经过被完全止住,你供给动用数据存款和储蓄Data Storage本事。

  1. final CharSequence[] items = {"Red", "Green", "Blue"}; 
  2.   
  3. AlertDialog.Builder builder = new AlertDialog.Builder(this); 
  4. builder.setTitle("Pick a color"); 
  5. builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() { 
  6.     public void onClick(DialogInterface dialog, int item) { 
  7.         Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); 
  8.     } 
  9. }); 
  10. AlertDialog alert = builder.create(); 

    setSingleChoiceItems(State of Qatar 的第二个参数是三个checkedItem整型数值,提醒了基于0的缺省选取项的职位。“-1”代表不会有暗中认可选择项。

 

mAlert = new AlertController(getContext(), this, getWindow());

速度对话框Progress Dialog的施用

    ProgressDialog是AlertDialog类的二个扩张,可认为三个未定义进度的职分呈现三个转悠轮形状的快慢动漫,可能为叁个点名进程的任务彰显一个进程条。

    能够省略地经过调用ProgressDialog.show(卡塔尔方法来显示三个速度对话框,而通过onCreateDialog(int卡塔尔(قطر‎回调管理那些对话框是可选的,如下所示:

  1. ProgressDialog.show(this, // context 
  2.     "", // title 
  3.     "Loading. Please wait...", // message 
  4.     true卡塔尔(قطر‎; //进程是不是是不分明的,那只和创造进程条有关 

速度对话框的缺省类型是四个筋斗轮,运营来看的是以下职能:

图片 9

    

 

也便是领头化了AlertDiaog的积极分子变量mAlert。

接轨回到大家的AlertDialog.Builder.create方法,在开立了二个AlertDialog之后,又实施了P.apply(dialog.mAlert卡塔尔;
大家了然这里的P是一个AlertController.AlertParams的变量,而dialog.mAlert是大家正好创造的AlertDialog中的三个AlertController类型的变量,大家来看一下apply方法的具体落到实处:

public void apply(AlertController dialog) {
            if (mCustomTitleView != null) {
                dialog.setCustomTitle(mCustomTitleView);
            } else {
                if (mTitle != null) {
                    dialog.setTitle(mTitle);
                }
                if (mIcon != null) {
                    dialog.setIcon(mIcon);
                }
                if (mIconId != 0) {
                    dialog.setIcon(mIconId);
                }
                if (mIconAttrId != 0) {
                    dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
                }
            }
            if (mMessage != null) {
                dialog.setMessage(mMessage);
            }
            if (mPositiveButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                        mPositiveButtonListener, null);
            }
            if (mNegativeButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                        mNegativeButtonListener, null);
            }
            if (mNeutralButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
                        mNeutralButtonListener, null);
            }
            if (mForceInverseBackground) {
                dialog.setInverseBackgroundForced(true);
            }
            // For a list, the client can either supply an array of items or an
            // adapter or a cursor
            if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
                createListView(dialog);
            }
            if (mView != null) {
                if (mViewSpacingSpecified) {
                    dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
                            mViewSpacingBottom);
                } else {
                    dialog.setView(mView);
                }
            } else if (mViewLayoutResId != 0) {
                dialog.setView(mViewLayoutResId);
            }
        }

观察了么?就是大家在起始化AlertDialog.Builder的时候设置的icon、title、message赋值给了AlertController.AlertParams,这里就是将大家开首化时候设置的属性值赋值给大家创设的Dialog对象的mAlert成员变量。。。。

世袭我们的AlertDialog.Builder.create方法,在实施了AlertController.AlertParams.apply方法之后又调用了:

dialog.setCancelable(P.mCancelable);

能够窥见这一个也是AertController.AlertParams的四个成员变量,大家在初叶化AlertDialog.Builder的时候也足以经过设置builder.setCancelable赋值,由于该属性为成员变量,所以暗中同意值为false,而大家并不曾经过builder.setCancelable修正那么些属性值,所以这里安装的dialog的cancelable的值为false。然后大家的create方法有设置了dialog的cancelListener和dismissListener并赶回了我们创设的Dialog对象。那样大家就获得到了笔者们的Dialog对象,然后大家调用了dialog的show方法用于体现dialog,好呢,这里咱们看一下show方法的切实可行落到实处:

public void show() {
        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;

        if (!mCreated) {
            dispatchOnCreate(null);
        }

        onStart();
        mDecor = mWindow.getDecorView();

        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }

        try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;

            sendShowMessage();
        } finally {
        }
    }

方法体的内容相当多,大家日益看,由于一发端mShowing变量用于表示前段时间dialog是还是不是正在彰显,由于大家刚刚最初调用试行show方法,所以这里的mShowing变量的值为false,所以if分支的剧情不会被推行,继续往下看:

if (!mCreated) {
            dispatchOnCreate(null);
        }

mCreated那么些调整变量调整dispatchOnCreate方法只被实行一遍,由于大家是第叁次举行,所以这里会履行dispatchOnCreate方法,好呢,我们看一下dispatchOnCreate方法的推行逻辑:

void dispatchOnCreate(Bundle savedInstanceState) {
        if (!mCreated) {
            onCreate(savedInstanceState);
            mCreated = true;
        }
    }

好啊,能够看出代码的施行逻辑很简短正是回调了Dialog的onCreate方法,那么onCreate方法内部又施行了这一个逻辑吗?由于大家创设的是AlertDialog对象,该指标世襲于Dialog,所以大家当时要求看一下AlertDialog的onCreate方法的举行逻辑:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

能够看看那其间除了调用super.onCreate方法之外就是调用了mAlert.installContent方法,而那边的super.onCreate方法就是调用的Dialog的onCreate方法,Dialog的onCreate方法只是贰个空的兑现逻辑,所以大家切实来看一下mAlert.installContent的贯彻逻辑。

public void installContent() {
        /* We use a custom title so never request a window title */
        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
        int contentView = selectContentView();
        mWindow.setContentView(contentView);
        setupView();
        setupDecor();
    }

能够见见这里完成Window窗口的页面设置结构开首化等操作,这里安装了mWindow对象为NO_TITLE,然后经过调用selectContentView设置Window对象的布局文件。

private int selectContentView() {
        if (mButtonPanelSideLayout == 0) {
            return mAlertDialogLayout;
        }
        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
            return mButtonPanelSideLayout;
        }
        // TODO: use layout hint side for long messages/lists
        return mAlertDialogLayout;
    }

能够看出这里透过施行selectContentView方法再次来到构造文件的id值,这里的暗中同意值是mAlertDialogLayout。从这么些艺术开始大家就把钦命布局文件的源委加载到内部存款和储蓄器中的Window对象中。大家那边看一下实际的构造文件。

mAlertDialogLayout = a.getResourceId(
                R.styleable.AlertDialog_layout, R.layout.alert_dialog);

也就是R.layout.alert_dialog的结构文件,有意思味的同桌能够看一下该布局文件的源码.
三回九转回到我们的installContent方法,在推行了mWindow.setContentView方法之后,又调用了setupView方法和setupDector方法,那七个章程的机要作用就是带头化布局文件中的组件和Window对象中的mDector成员变量,这里就不在详细的辨证。

接下来回来大家的show方法,在施行了dispatchOnCreate方法之后大家又调用了onStart方法,这些措施首要用于设置ActionBar,这里不做过多的求证,然后初阶化WindowManager.LayoutParams对象,并最后调用我们的mWindowManager.addView(卡塔尔方法。

O(∩_∩)O哈哈~,到了这一步我们要是看了上一篇Acitivty布局绘制流程的话,就活该清楚顺着这些措施漫天Dialog的分界面就能够被绘制出来了。

终极我们调用了sendShowMessage方法,能够看一下以此点子的落到实处:

private void sendShowMessage() {
        if (mShowMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mShowMessage).sendToTarget();
        }
    }

此间会发送二个Dialog已经突显的异步音讯,该音讯最后会在ListenersHandler中的handleMessage方法中被施行:

private static final class ListenersHandler extends Handler {
        private WeakReference<DialogInterface> mDialog;

        public ListenersHandler(Dialog dialog) {
            mDialog = new WeakReference<DialogInterface>(dialog);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DISMISS:
                    ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
                    break;
                case CANCEL:
                    ((OnCancelListener) msg.obj).onCancel(mDialog.get());
                    break;
                case SHOW:
                    ((OnShowListener) msg.obj).onShow(mDialog.get());
                    break;
            }
        }
    }

由于大家的msg.what = SHOW,所以会试行OnShowListener.onShow方法,那么那么些OnShowListener是曾几何时赋值的吧?还记得大家协会AlertDialog.Builder么?

alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                    @Override
                    public void onShow(DialogInterface dialog) {

                    }
                });

如此就为大家的AlertDialog.Builder设置了OnShowListener,能够看一下setOnShowListener方法的实际实现:

public void setOnShowListener(OnShowListener listener) {
        if (listener != null) {
            mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
        } else {
            mShowMessage = null;
        }
    }

这么就为大家的Dialog中的mListenersHandler布局了Message对象,并且当大家在Dialog中发送showMessage的时候被mListenersHandler所接受。。。。

注:
这里说一下我们平日支付中若成立的Dialog使用的Context对象不是Activity,就能够报出:

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

的特别,那是由于WindowManager.addView方法最终会调用ViewRootImpl.setView方法,而此刻会有mToken的自己切磋,若大家传入的Context对象不是Activity,那时候的mToken为空,就会面世上述难题。。。

总结:

Dialog和Activity的显得逻辑是平时的都是内处那一个Window对象,用WIndow对象实现分界面包车型大巴加载与体现逻辑;

Dialog中的Window对象与Activity中的Window对象是相像的,都对应着二个WindowManager对象;

Dialog相关的多少个类:Dialog,AlertDialog,AlertDialog.Builder,AlertController,AlertController.AlertParams,当中Dialog是窗口的父类,主要完毕Window对象的开头化和局地共有逻辑,而AlertDialog是具体的Dialog的操作达成类,AlertDialog.Builder类是AlertDialog的中间类,首要用以组织AlertDialog,AlertController是AlertDialog的调整类,AlertController.AlertParams类是调节参数类;

构造展现Dialog的相仿流程,构造AlertDialog.Builder,然后设置种种品质,最终调用AlertDialog.Builder.create方法获取AlertDialog对象,并且create方法中会施行,布局AlertDialog,设置dialog各个质量的操作。最终大家调用Dialog.show方法体现窗口,开头化Dialog的布局文件,Window对象等,然后实施mWindowManager.addView方法,初始推行绘制View的操作,并最终将Dialog展现出来;

TAG标签:
版权声明:本文由美高梅网投平台发布于新闻中心,转载请注明出处:未关闭AlertDialog引发的溢出,日期选择对话框