解决隐藏键盘时出现的‘System services not available to Activities before onCreate()’异常
解决Dialog中隐藏软键盘触发的System Services异常问题
问题场景
有开发者反馈:在Activity的onCreate方法完成后初始化自定义Dialog类MyPersonalDialog,调用showMyDialog显示弹窗,点击弹窗的取消按钮时,调用InputHelper的hideKeyboard方法出现了如下异常:
java.lang.IllegalStateException: System services not available to Activities before onCreate()
问题原因
分析原代码后发现,问题出在InputHelper的hideKeyboard方法设计上:
原方法需要传入外部Activity实例来获取InputMethodManager,但存在两个关键隐患:
- 自定义Dialog中可能没有正确持有有效的Activity实例(比如错误传递了Application Context,或者Activity引用的状态出现异常);
- 即便在Activity onCreate后初始化Dialog,调用该方法时,传入的Activity实例可能因上下文引用问题,被判定为未完成onCreate流程,进而导致获取系统服务失败。
解决方案
我们可以修改InputHelper,去掉对外部Activity的依赖,直接通过持有的Context获取系统服务——毕竟隐藏软键盘只需要目标View的windowToken即可:
修正后的InputHelper类
class InputHelper(val context: Context){ fun showDialogKeyboard() { val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) } fun hideKeyboard(view: View) { val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputManager.hideSoftInputFromWindow(view.windowToken, 0); } }
同步修改MyPersonalDialog的取消按钮逻辑
去掉无效的Activity参数,直接传入弹窗中的输入View即可:
class MyPersonalDialog(private val context: Context){ fun showMyDialog(){ val builder = AlertDialog.Builder(context) val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val view = layoutInflater.inflate(R.layout.dialog_edit_list_title, null) view.renameListTitle.requestFocus() val inputHelper = InputHelper(context) inputHelper.showDialogKeyboard() builder.setView(view) builder.setNegativeButton(R.string.cancel) { _, _ -> inputHelper.hideKeyboard(view) } // 别忘了调用create()和show()来显示弹窗 builder.create().show() } }
方案说明
- 直接使用
InputHelper初始化时传入的Context获取系统服务,只要这个Context是有效的Activity上下文(比如初始化Dialog时传入的Activity实例),就能安全获取InputMethodManager; - 隐藏软键盘只需要目标输入View的
windowToken,完全不需要依赖Activity实例,既简化了代码结构,又彻底规避了生命周期相关的异常。
内容的提问来源于stack exchange,提问作者Pavel Malinovskij
相关产品推荐
相关产品推荐

