Android Studio Firebase登录注册崩溃:空值参数异常求助
邮箱登录注册模块启动崩溃问题(基于Firebase)
问题概述
基于Firebase开发Android登录注册系统,Facebook和Google登录功能正常,但邮箱登录注册模块在应用启动时直接崩溃,报错java.lang.IllegalArgumentException: Given String is empty or null。排查后确认是启动阶段获取空EditText值导致的异常。
错误日志
FATAL EXCEPTION: main Process: com.example.navotasapp, PID: 12865 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.navotasapp/com.example.navotasapp.MainActivity}: java.lang.IllegalArgumentException: Given String is empty or null at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.IllegalArgumentException: Given String is empty or null at com.google.android.gms.common.internal.Preconditions.checkNotEmpty(com.google.android.gms:play-services-basement@@18.2.0:2) at com.google.firebase.auth.EmailAuthProvider.getCredential(com.google.firebase:firebase-auth@@22.3.0:1) at com.example.navotasapp.MainActivity.onCreate(MainActivity.kt:74) at android.app.Activity.performCreate(Activity.java:8000) at android.app.Activity.performCreate(Activity.java:7984) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
代码问题分析
查看MainActivity.kt的onCreate方法,存在以下关键错误:
- 启动时直接调用空值敏感API:在
onCreate中直接执行EmailAuthProvider.getCredential(email, password),此时EditText还未输入内容,email和password为空字符串,触发Firebase的参数非空校验异常。 - 错误时机执行登录请求:在
onCreate中直接调用auth.signInWithEmailAndPassword(email, password),同样使用空值,不仅会崩溃,逻辑上也不应该在启动时自动执行登录。 - 点击事件使用旧值:
btnSubmit的点击事件中,使用的是onCreate阶段获取的空email和password,而非用户输入后的最新值。 - 重复设置点击事件:
registerNow文本的点击事件被重复设置两次,属于冗余代码。 - 重复设置布局:先调用
setContentView(R.layout.activity_main),之后又通过binding重新设置布局,可能导致控件查找失效或冲突。
修复方案
修正后的MainActivity.kt代码如下,核心是将所有需要用户输入的操作移到点击事件内部,并移除启动阶段的无效API调用:
class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding private lateinit var auth: FirebaseAuth private lateinit var googleSignInClient: GoogleSignInClient private lateinit var callbackManager: CallbackManager private lateinit var editTextEmail: EditText private lateinit var editTextPassword: EditText private lateinit var buttonReg: MaterialButton private lateinit var progressBar: ProgressBar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 统一使用ViewBinding设置布局,避免重复调用setContentView binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 通过binding获取控件,替代findViewById editTextEmail = binding.email editTextPassword = binding.etPassword buttonReg = binding.loginBtn progressBar = binding.progressBar auth = FirebaseAuth.getInstance() val textView: TextView = binding.registerNow // 登录按钮点击事件:仅在用户点击时获取输入值并验证 buttonReg.setOnClickListener { val email: String = editTextEmail.text.toString().trim() val password: String = editTextPassword.text.toString().trim() if (email.isEmpty() || password.isEmpty()) { Toast.makeText(this, "Email and password cannot be empty", Toast.LENGTH_SHORT).show() } else { progressBar.visibility = View.VISIBLE auth.signInWithEmailAndPassword(email, password) .addOnCompleteListener(this) { task -> progressBar.visibility = View.GONE if (task.isSuccessful) { Log.d(TAG, "signInWithEmail:success") toast("Login Successful.") Intent(this, HomeActivity::class.java).apply { startActivity(this) finish() } } else { Log.w(TAG, "signInWithEmail:failure", task.exception) toast("Authentication failed.") } } } } // 注册跳转点击事件:保留一次即可 textView.setOnClickListener { val intent = Intent(applicationContext, SignUpActivity::class.java) startActivity(intent) finish() } // 注册按钮点击事件:确保获取最新输入值(注意:若注册按钮为独立控件,需修改对应ID) val btnSubmit: MaterialButton = binding.loginBtn btnSubmit.setOnClickListener { val email: String = editTextEmail.text.toString().trim() val password: String = editTextPassword.text.toString().trim() if (email.isEmpty() || password.isEmpty()) { Toast.makeText(this, "Email and password cannot be empty", Toast.LENGTH_SHORT).show() return@setOnClickListener } progressBar.visibility = View.VISIBLE auth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(this) { task -> progressBar.visibility = View.GONE if (task.isSuccessful) { Log.d(TAG, "createUserWithEmail:success") toast("Account successfully created!") } else { Log.w(TAG, "createUserWithEmail:failure", task.exception) toast("Authentication failed.") } } } // 侧边栏及FAB设置 binding.appBarMain.fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show() } val drawerLayout: DrawerLayout = binding.drawerLayout val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration(setOf( R.id.nav_home), drawerLayout) setupActionBarWithNavController(navController, appBarConfiguration) // Google登录设置 val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.default_web_client_id)) .requestEmail() .build() googleSignInClient = GoogleSignIn.getClient(this, gso) binding.googleSigninBtn.setOnClickListener { signInGoogle() } // Facebook登录设置:移出Google点击事件内部,避免每次点击Google才绑定 FacebookSdk.sdkInitialize(applicationContext) callbackManager = CallbackManager.Factory.create() binding.facebookSigninBtn.setOnClickListener { LoginManager.getInstance().logInWithReadPermissions(this, listOf("public_profile")) } LoginManager.getInstance().registerCallback(callbackManager, object : FacebookCallback<LoginResult> { override fun onSuccess(loginResult: LoginResult) { startActivity(Intent(this@MainActivity, HomeActivity::class.java)) finish() } override fun onCancel() {} override fun onError(exception: FacebookException) {} }) } public override fun onStart() { super.onStart() val currentUser = auth.currentUser if (currentUser != null) { startActivity(Intent(this, HomeActivity::class.java)) finish() } } private fun toast(message: String) { Toast.makeText(baseContext, message, Toast.LENGTH_SHORT).show() } private fun signInGoogle(){ val signInIntent = googleSignInClient.signInIntent launcher.launch(signInIntent) } private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) handleResults(task) } } private fun handleResults(task: Task<GoogleSignInAccount>) { if (task.isSuccessful){ val account: GoogleSignInAccount? = task.result account?.let { updateUI(it) } }else{ Toast.makeText(this, task.exception.toString(), Toast.LENGTH_SHORT).show() } } private fun updateUI(account: GoogleSignInAccount) { val credential = GoogleAuthProvider.getCredential(account.idToken, null) auth.signInWithCredential(credential).addOnCompleteListener{ if (it.isSuccessful) { val intent = Intent(this, HomeActivity::class.java).apply { putExtra("email", account.email) putExtra("name", account.displayName) } startActivity(intent) }else{ Toast.makeText(this, it.exception.toString(), Toast.LENGTH_SHORT).show() } } } override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.main, menu) return true } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment_content_main) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } companion object { private const val TAG = "MainActivity" } }
关键修复点说明
- 移除
onCreate中启动阶段的EmailAuthProvider.getCredential和auth.signInWithEmailAndPassword调用,这些操作应该在用户输入后触发。 - 所有获取EditText值的操作都移到对应的点击事件内部,确保拿到用户输入的最新数据。
- 统一使用ViewBinding管理控件,避免重复设置布局和冗余的
findViewById调用。 - 将Facebook登录的绑定逻辑移出Google按钮的点击事件,避免每次点击Google才初始化Facebook回调。
- 添加
progressBar的显示/隐藏逻辑,优化用户体验。
内容的提问来源于stack exchange,提问作者sushibun
相关产品推荐
相关产品推荐

