Room数据库登录验证崩溃求助:输入含特殊字符点击按钮崩溃
问题描述
我在LoginFragment中实现了邮箱和密码输入框,需求是验证数据库中的邮箱与密码是否匹配。点击按钮时,数据库需读取数据并通过邮箱+密码查找对应账户。assets目录下已存放数据库文件,但输入框包含特殊字符时,点击按钮会导致应用崩溃。以下是相关代码:
数据库类
package Room.Database import Room.DAO.DAO import Room.Repository.Admindata import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase @Database (entities = [Admindata::class], version = 2, exportSchema = true) abstract class AdminDatabase:RoomDatabase(){ abstract fun getDAO(): DAO companion object{ fun getadminDB(context: Context):AdminDatabase{ return Room.databaseBuilder(context.applicationContext,AdminDatabase::class.java,"admindatabase").createFromAsset("SQLDB/dbforpetproject.db").build() } } }
DAO接口
package Room.DAO import Room.Repository.Admindata import androidx.room.Dao import androidx.room.Query @Dao interface DAO { @Query("select * from admin_table where email = :email") suspend fun findbyEmail(email:String) : Admindata @Query("select * from admin_table where password = :password") suspend fun findbypassword(password:String) : Admindata }
实体类Admindata
package Room.Repository import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName= "admin_table") data class Admindata( @PrimaryKey val id:Int = 1, @ColumnInfo(name = "email") val email:String = "admin@gmail.com", @ColumnInfo(name = "password") val password:String = "12345678" )
LoginFragment代码
package com.example.myapplication import Room.Database.AdminDatabase import Room.Repository.Admindata import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.example.myapplication.databinding.FragmentLoginBinding import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class LoginFragment : Fragment() { private lateinit var binding : FragmentLoginBinding private lateinit var db:AdminDatabase private lateinit var admin:Admindata val scope = CoroutineScope(CoroutineName("Scope")) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) db = AdminDatabase.getadminDB(requireContext()) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentLoginBinding.inflate(inflater) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.continuebutton.setOnClickListener { if(binding.EmailSpace.length() == 0){ Toast.makeText(context,"The space is empty write email",Toast.LENGTH_SHORT).show() } if(binding.PasswordSpace.length() == 0){ Toast.makeText(context,"The space is empty write password",Toast.LENGTH_SHORT).show() } if(binding.PasswordSpace.length() <8){ Toast.makeText(context,"Password is too small",Toast.LENGTH_SHORT).show() } if(binding.EmailSpace.length() >0){ // 我的错误实现 scope.launch { findbyEmail(email = admin.email) } findNavController().navigate(R.id.action_loginFragment_to_lastfragment) } else{ Toast.makeText(context,"Email is wrong",Toast.LENGTH_SHORT).show() } // 我的错误实现 if(binding.PasswordSpace.length() >0){ // 我的错误实现 scope.launch { findbyPassword(password = admin.password) } findNavController().navigate(R.id.action_loginFragment_to_lastfragment) } else{ Toast.makeText(context,"Password is wrong",Toast.LENGTH_SHORT).show() // 我的错误实现 } } } @Override private suspend fun findbyEmail(email:String){ val tuple = db.getDAO().findbyEmail(email) if(tuple.email != email){ Toast.makeText(context,"Email is wrong",Toast.LENGTH_SHORT).show() } } @Override private suspend fun findbyPassword(password:String){ val tuple = db.getDAO().findbypassword(password) if(tuple.password != password){ Toast.makeText(context,"Password is wrong",Toast.LENGTH_SHORT).show() } } }
修复方案
1. 修正DAO接口逻辑
当前DAO分别查询邮箱和密码,既不符合"同时匹配邮箱+密码"的业务逻辑,且查询无结果时会抛出EmptyResultSetException导致崩溃。修改为同时验证邮箱和密码,并返回可空对象:
package Room.DAO import Room.Repository.Admindata import androidx.room.Dao import androidx.room.Query @Dao interface DAO { // 同时验证邮箱和密码,返回可空对象避免无结果时崩溃 @Query("select * from admin_table where email = :email and password = :password") suspend fun findByEmailAndPassword(email: String, password: String): Admindata? }
2. 重构LoginFragment核心逻辑
- 移除未初始化的
admin变量,直接获取输入框文本 - 统一前端校验流程,避免分散判断
- 协程内完成数据库验证,验证通过后再跳转页面
- 确保Toast在主线程调用,避免线程异常
- 处理数据库查询无结果的情况
修改后的代码:
package com.example.myapplication import Room.Database.AdminDatabase import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.example.myapplication.databinding.FragmentLoginBinding import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class LoginFragment : Fragment() { private lateinit var binding: FragmentLoginBinding private lateinit var db: AdminDatabase // 使用IO线程处理数据库操作,主线程处理UI private val scope = CoroutineScope(Dispatchers.IO) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) db = AdminDatabase.getadminDB(requireContext()) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentLoginBinding.inflate(inflater) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.continuebutton.setOnClickListener { val inputEmail = binding.EmailSpace.text.toString().trim() val inputPassword = binding.PasswordSpace.text.toString().trim() // 前端校验 when { inputEmail.isEmpty() -> { showToast("请输入邮箱") return@setOnClickListener } inputPassword.isEmpty() -> { showToast("请输入密码") return@setOnClickListener } inputPassword.length < 8 -> { showToast("密码长度不能少于8位") return@setOnClickListener } else -> { // 数据库验证 scope.launch { val matchedAdmin = db.getDAO().findByEmailAndPassword(inputEmail, inputPassword) // 切换到主线程处理UI withContext(Dispatchers.Main) { if (matchedAdmin != null) { findNavController().navigate(R.id.action_loginFragment_to_lastfragment) } else { showToast("邮箱或密码错误") } } } } } } } // 封装Toast,确保在主线程调用 private fun showToast(message: String) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
3. 额外注意事项
- 确认assets目录结构:
createFromAsset("SQLDB/dbforpetproject.db")需与实际文件路径一致,确保assets下存在SQLDB文件夹及对应数据库文件 - Room参数化查询会自动处理特殊字符转义,无需手动处理,避免SQL注入风险
- 确保Room依赖版本一致,避免版本冲突导致异常
内容的提问来源于stack exchange,提问作者user20498005
相关产品推荐
相关产品推荐

