You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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方法,存在以下关键错误:

  1. 启动时直接调用空值敏感API:在onCreate中直接执行EmailAuthProvider.getCredential(email, password),此时EditText还未输入内容,email和password为空字符串,触发Firebase的参数非空校验异常。
  2. 错误时机执行登录请求:在onCreate中直接调用auth.signInWithEmailAndPassword(email, password),同样使用空值,不仅会崩溃,逻辑上也不应该在启动时自动执行登录。
  3. 点击事件使用旧值:btnSubmit的点击事件中,使用的是onCreate阶段获取的空email和password,而非用户输入后的最新值。
  4. 重复设置点击事件:registerNow文本的点击事件被重复设置两次,属于冗余代码。
  5. 重复设置布局:先调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:27:03