问题解决:dialogfragment无法监听监听返回键

本文将指导您如何在Android中通过在Dialog中设置OnKeyListener来处理按键事件,特别是处理返回键和菜单键的功能。

 

转载:http://blog.youkuaiyun.com/liyuxp/article/details/17252163


在onCreateView中加入

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. this.getDialog().setOnKeyListener(new OnKeyListener()  
  2.          {  
  3.   
  4.             @Override  
  5.             public boolean onKey(DialogInterface arg0, int keyCode, KeyEvent arg2) {  
  6.                 // TODO Auto-generated method stub  
  7.                 if (keyCode == KeyEvent.KEYCODE_BACK) {  
  8.   
  9.                     return true;  
  10.                 }else if(keyCode == KeyEvent.KEYCODE_MENU) {  
  11.   
  12.                     return true;  
  13.                 }  
  14.                 return false;  
  15.             }  
  16.         });  

源码来自:https://pan.quark.cn/s/41b9d28f0d6d 在信息技术领域中,jQuery作为一个广受欢迎的JavaScript框架,显著简化了诸多操作,包括对HTML文档的遍历、事件的管理、动画的设计以及Ajax通信等。 本篇文档将深入阐释如何运用jQuery达成一个图片自动播放的功能,这种效果常用于网站的轮播展示或幻灯片演示,有助于优化用户与页面的互动,使网页呈现更加动态的视觉体验。 为了有效实施这一功能,首先需掌握jQuery的核心操作。 通过$符号作为接口,jQuery能够迅速选取DOM组件,例如$("#id")用于选取具有特定ID的元素,而$(".class")则能选取所有应用了某类class的元素。 在选定元素之后,可以执行多种行为,诸如事件监听、样式的变更、内容的更新以及动画的制作等。 关于“一个基于jQuery的图片自动播放功能”,首要任务是准备一组图片素材,这些素材将被整合至一个容器元素之中。 例如,可以构建一个div元素,将其宽度设定为单张图片的尺寸,再借助CSS实现溢出内容的隐藏,从而构建出水平滚动的初始框架。 ```html<div id="slider"> <img src="image1.jpg" alt="Image 1"> <img src="image2.jpg" alt="Image 2"> <!-- 更多图片内容... --></div>```接着,需要编写jQuery脚本以实现图片的自动切换。 这通常涉及到定时器的运用,以设定周期性间隔自动更换当前显示的图片。 通过使用`.fadeOut()`和`.fadeIn()`方法,能够实现图片间的平滑过渡,增强视觉效果。 ```javascript$(document).re...
<think>我们讨论的是在Android开发中,Dialog被dismiss()后再show(),返回监听器是否会失效的问题。 首先,需要明确的是,Dialog在dismiss()后,通常会移除其自身的窗口和视图,同时也会移除一些监听器。但是,当我们再次show()时,Dialog会重新创建窗口和视图,并重新设置监听器(前提是我们正确设置了监听器)。 关点在于:我们在哪里设置的返回监听器(例如通过setOnKeyListener)?以及我们设置监听器的时机。 常见的做法有两种: 1. 在创建Dialog时设置返回监听器(例如在构造Dialog后立即设置)。 2. 在每次show()之前设置返回监听器。 如果我们只在第一次创建Dialog时设置了监听器,那么当Dialog被dismiss()后,再次show()时,由于Dialog已经被销毁(具体来说,Dialog的窗口被移除,但Dialog对象可能还在),当重新show()时,Dialog会重新创建窗口,但之前设置的监听器是否还绑定在新的窗口上呢?这取决于我们设置监听器的方式。 实际上,如果我们使用Dialog的setOnKeyListener()方法,这个监听器是设置在Dialog本身,而不是设置在每次显示的窗口上。因此,即使我们dismiss()后再show(),Dialog对象还是同一个,所以设置的监听器依然有效。 但是,有一个特殊情况:如果我们使用DialogFragment,并且在DialogFragment中设置了返回监听,那么我们需要确保在每次Dialog显示时重新设置监听器(因为DialogFragment在dismiss()后可能会被销毁,再次显示时会重新创建Dialog)。不过,对于普通的Dialog,通常不会出现监听器失效的情况。 然而,有一种情况可能会导致失效:如果我们使用了系统返回监听(比如在Activity监听返回,并判断当前Dialog是否显示,然后决定是否消费事件),那么在Dialog被dismiss()后,我们可能忘记重新设置这个监听逻辑,导致再次show()时,监听逻辑不存在。 但如果是直接对Dialog设置返回监听,代码通常如下: ```java Dialog dialog = new Dialog(context); dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { // 处理返回 return true; // 表示消费事件 } return false; } }); ``` 在这种情况下,即使我们dismiss()后再show(),同一个Dialog对象的OnKeyListener仍然存在,所以返回监听器不会失效。 但是,如果我们每次show()之前都重新创建了一个新的Dialog对象,那么我们必须重新设置监听器,否则新的Dialog就没有设置监听器。 所以,问题的答案是:如果我们复用同一个Dialog对象,并且我们在这个Dialog对象上设置了返回监听,那么dismiss()后再show(),监听器不会失效。但如果我们每次show()都新建一个Dialog对象,并且没有设置监听器,那么就会失效。 下面我们用一个代码示例来说明: ```java public class MainActivity extends Activity { private Dialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 创建Dialog dialog = new Dialog(this); dialog.setContentView(R.layout.dialog_layout); // 设置返回监听 dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { Toast.makeText(MainActivity.this, "Back key pressed in dialog", Toast.LENGTH_SHORT).show(); // 可以选择消费掉返回事件,这样对话框不会消失 // return true; // 或者不消费,让对话框消失(默认行为) // return false; // 这里我们消费事件,对话框不消失 return true; } return false; } }); Button showButton = findViewById(R.id.show_button); showButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.show(); } }); Button dismissButton = findViewById(R.id.dismiss_button); dismissButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); } } ``` 在这个例子中,我们创建了一个Dialog并设置了返回监听器。当我们按下返回时,会显示一个Toast,并且返回true消费事件(所以对话框不会因为返回而消失)。我们通过两个按钮分别显示和隐藏对话框。 即使我们多次dismiss()和show()这个对话框,返回监听器依然有效,因为Dialog对象是同一个,监听器一直绑定在它上面。 但是,如果我们每次show()的时候都创建一个新的Dialog,比如: ```java showButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 每次show都新建一个Dialog dialog = new Dialog(MainActivity.this); dialog.setContentView(R.layout.dialog_layout); // 注意:这里没有设置返回监听器,所以新的Dialog没有监听器 dialog.show(); } }); ``` 那么,新的Dialog就没有设置返回监听器,自然返回监听器就“失效”了(实际上是根本没有设置给新的Dialog)。 因此,为了避免失效,我们需要确保每次创建新的Dialog时都要重新设置监听器。或者,更好的做法是复用同一个Dialog对象。 总结:复用同一个Dialog对象,并且在该对象上设置返回监听器,则dismiss()后再show()不会失效。如果每次show()都创建新的Dialog,则必须重新设置监听器。 下面提出相关问题: </think>在 Android 开发中,当 `Dialog` 被 `dismiss()` 后再 `show()`,**返回监听器通常会失效**,原因在于 Dialog 的底层实现机制。以下是详细分析和解决方案: ### 原因分析 1. **监听器绑定机制**: - 系统返回监听器 (`OnKeyListener`) 是绑定到 Dialog 的 `Window` 对象上的 - 调用 `dismiss()` 时会销毁 Dialog 的 `DecorView` 和 `Window` - 再次 `show()` 时新建的 `Window` 不会自动恢复之前的监听器 2. **Dialog 生命周期**: ```mermaid graph LR A[show] --> B[Window 创建] B --> C[监听器绑定] C --> D[dismiss] D --> E[Window 销毁] E --> F[show 重新调用] F --> G[新Window创建]<-->H[监听器未绑定] ``` ### 解决方案(Kotlin 实现) 每次 `show()` 时重新绑定监听器是最可靠的方案: ```kotlin class MainActivity : AppCompatActivity() { private lateinit var dialog: AlertDialog override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化 Dialog(但不立即显示) dialog = AlertDialog.Builder(this) .setTitle("警告") .setMessage("确认退出吗?") .create() findViewById<Button>(R.id.btn_show).setOnClickListener { showDialogWithBackListener() } } private fun showDialogWithBackListener() { // 关:每次 show() 前重新设置返回监听 dialog.setOnKeyListener { _, keyCode, event -> if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) { Toast.makeText(this, "返回被拦截", Toast.LENGTH_SHORT).show() true // 消费事件 } else false } // 防止 Window 未初始化导致的崩溃 if (!dialog.isShowing) { dialog.show() } } } ``` ### 关代码解释 1. **监听器重置**: ```kotlin dialog.setOnKeyListener { ... } // 每次show前重新绑定 ``` - 必须在每次 `show()` 前调用,确保绑定到新创建的 Window 2. **防崩溃检查**: ```kotlin if (!dialog.isShowing) { dialog.show() } ``` - 避免重复显示导致的 `WindowLeaked` 异常 3. **事件消费**: ```kotlin if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) { // ... 处理逻辑 return@setOnKeyListener true // 拦截返回 } ``` ### 替代方案(DialogFragment) 使用 `DialogFragment` 可自动管理生命周期: ```kotlin class MyDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return AlertDialog.Builder(requireContext()) .setTitle("警告") .setOnKeyListener { _, keyCode, event -> if (keyCode == KeyEvent.KEYCODE_BACK) { // 处理返回 true } else false } .create() } // 显示方法 fun show(manager: FragmentManager) { show(manager, "my_dialog") } } // 调用方式 MyDialogFragment().show(supportFragmentManager) ``` ### 最佳实践建议 1. **避免重复创建**:复用 Dialog 实例但每次 show 前重置监听 2. **使用 FragmentTransaction**:`DialogFragment` 通过 `show()`/`dismiss()` 自动处理重建 3. **测试场景**: - 旋转屏幕后检查监听器 - 连续 dismiss/show 三次测试稳定性
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值