适配Fragment后App启动崩溃,Kotlin登录注册SharedPreferences问题排查
问题描述
我正在开发一款基于Kotlin的Android应用,打算用SharedPreferences实现登录注册功能,但运行时应用直接崩溃,无法启动。代码原本基于Activity编写,改成Fragment后出现这个问题,不确定是否和适配有关。我是Android Studio和Kotlin新手。
原代码
Login.kt
class Login : Fragment() { private lateinit var fbinding: FragmentLoginBinding var txtUsu: EditText? = null var txtPass: EditText? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) txtUsu = fbinding.etUsuarioL.findViewById(R.id.et_usuarioL) txtPass = fbinding.etContrasenaL.findViewById(R.id.et_contrasenaL) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { fbinding = FragmentLoginBinding.inflate(layoutInflater) navLogin() return fbinding.root } fun login(view: View){ var pref = this.activity?.getSharedPreferences(txtUsu?.text.toString(), Context.MODE_PRIVATE) var pass = pref?.getString("Pass", "") if (pass == txtPass?.text.toString()){ navLogin() }else{ Toast.makeText(this.activity, "Error en las credenciales, intente de nuevo", Toast.LENGTH_SHORT).show() txtUsu?.setText("") txtPass?.setText("") } } private fun navLogin(){ fbinding.btnInises.setOnClickListener { Navigation.findNavController(fbinding.root).navigate(R.id.action_login_to_menu2) } } }
registro.kt(SignUp)
class registro : Fragment() { private lateinit var fBinding: FragmentRegistroBinding var txtUsu: EditText? = null var txtPass: EditText? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) fBinding = FragmentRegistroBinding.inflate(layoutInflater) txtUsu = fBinding.etUsuarioR.findViewById(R.id.et_usuarioR) txtPass = fBinding.etContraseAR.findViewById(R.id.et_contraseñaR) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_registro, container, false) } fun guardar(view: View){ var pref = this.activity?.getSharedPreferences(txtUsu?.text.toString(), Context.MODE_PRIVATE) var editor = pref?.edit() editor?.putString("pass", txtPass?.text.toString()) Toast.makeText(this.activity, "Guardado", Toast.LENGTH_SHORT).show() txtUsu?.setText("") txtPass?.setText("") } fun irLogin(){ fBinding.btnAceptarR.setOnClickListener{ Navigation.findNavController(fBinding.root).navigate(R.id.action_registro_to_login) } } }
崩溃原因及修复方案
核心问题总结
崩溃主要源于Fragment生命周期使用错误、ViewBinding初始化时机错误、空指针风险以及SharedPreferences操作不规范,和Fragment适配直接相关。
具体修复点
1. Login.kt修复
- 移除
onCreate中的控件初始化:Fragment的onCreate阶段未创建视图,fbinding此时未初始化,直接调用会触发UninitializedPropertyAccessException,所有控件初始化移到onCreateView中。 - 简化EditText获取:ViewBinding生成的
fbinding.etUsuarioL本身就是对应控件,无需额外调用findViewById。 - 统一SharedPreferences键名:注册时存的是
"pass",登录时取的是"Pass",大小写不匹配导致验证失败,统一为小写"pass"。 - 调整登录逻辑:
login方法中调用navLogin()是重复设置点击事件,应直接执行导航;增加空输入判断,避免空字符串问题。 - 使用非空类型:将
txtUsu、txtPass改为lateinit var非空类型,减少空安全处理麻烦。
2. registro.kt修复
- 在
onCreateView中初始化ViewBinding:Fragment的layoutInflater在onCreate阶段不可用,必须在onCreateView中初始化绑定,且返回fBinding.root保证视图一致。 - 提交SharedPreferences编辑:调用
editor?.putString后必须执行editor?.apply()或editor?.commit(),否则数据不会保存。 - 调用点击事件设置方法:
irLogin方法需要在onCreateView中调用,否则按钮点击事件无效。 - 增加空输入判断:避免用户输入空字符串时创建无效的SharedPreferences文件。
修复后的代码
Login.kt
class Login : Fragment() { private lateinit var fbinding: FragmentLoginBinding private lateinit var txtUsu: EditText private lateinit var txtPass: EditText override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { fbinding = FragmentLoginBinding.inflate(inflater, container, false) txtUsu = fbinding.etUsuarioL txtPass = fbinding.etContrasenaL navLogin() return fbinding.root } fun login(view: View) { val username = txtUsu.text.toString().trim() val password = txtPass.text.toString().trim() if (username.isEmpty() || password.isEmpty()) { Toast.makeText(activity, "请输入用户名和密码", Toast.LENGTH_SHORT).show() return } val pref = activity?.getSharedPreferences(username, Context.MODE_PRIVATE) val savedPass = pref?.getString("pass", "") if (savedPass == password) { Navigation.findNavController(fbinding.root).navigate(R.id.action_login_to_menu2) } else { Toast.makeText(activity, "账号或密码错误,请重试", Toast.LENGTH_SHORT).show() txtUsu.setText("") txtPass.setText("") } } private fun navLogin() { fbinding.btnInises.setOnClickListener { login(it) } } }
registro.kt(SignUp)
class registro : Fragment() { private lateinit var fBinding: FragmentRegistroBinding private lateinit var txtUsu: EditText private lateinit var txtPass: EditText override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { fBinding = FragmentRegistroBinding.inflate(inflater, container, false) txtUsu = fBinding.etUsuarioR txtPass = fBinding.etContraseAR irLogin() return fBinding.root } fun guardar(view: View) { val username = txtUsu.text.toString().trim() val password = txtPass.text.toString().trim() if (username.isEmpty() || password.isEmpty()) { Toast.makeText(activity, "请输入用户名和密码", Toast.LENGTH_SHORT).show() return } val pref = activity?.getSharedPreferences(username, Context.MODE_PRIVATE) val editor = pref?.edit() editor?.putString("pass", password) editor?.apply() Toast.makeText(activity, "注册成功", Toast.LENGTH_SHORT).show() txtUsu.setText("") txtPass.setText("") } private fun irLogin() { fBinding.btnAceptarR.setOnClickListener { Navigation.findNavController(fBinding.root).navigate(R.id.action_registro_to_login) } // 假设注册按钮id为btnGuardarR,绑定guardar方法 fBinding.btnGuardarR?.setOnClickListener { guardar(it) } } }
内容的提问来源于stack exchange,提问作者MrGoose
相关产品推荐
相关产品推荐

