我正在使用Firestore在数据库中注册用户。
为了方便起见,我决定将所有注册代码放在ListenableWorker
中,以利用WorkManager库。
此类称为RegisterUserWorker
。
在此任务中,我执行对Firestore的调用以将用户添加到数据库:
class RegisterTask(ctx: Context, params: WorkerParameters) : ListenableWorker(ctx, params) {
private val auth = FirebaseAuth.getInstance()
private lateinit var countDownLatch: CountDownLatch
private val taskResult = arrayOf(Result.failure())
private lateinit var emailAddress: String
private lateinit var password: String
override fun startWork(): ListenableFuture<Result> {
// Based on this post: https://stackoverflow.com/a/50425201
println("run attempt count: $runAttemptCount")
countDownLatch = CountDownLatch(1)
val username = inputData.getString("username")!!
password = inputData.getString("password")!!
emailAddress = inputData.getString("emailAddress")!!
val countryOfOrigin = inputData.getString("countryOfOrigin")!!
val dateOfBirth = inputData.getString("dateOfBirth")!!
// var awaitsCountDown = false
auth.createUserWithEmailAndPassword(emailAddress, password).addOnCompleteListener { task ->
// awaitsCountDown = true
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.w(this.TAG(), "createUserWithEmailAndPassword:success")
val uid = FirebaseAuth.getInstance().uid
if (uid is String) {
// uid exists because user creation succeeded
val user = User(
// Usernames are case insensitive
username = username,
userId = uid,
emailAddress = emailAddress,
countryOfOrigin = countryOfOrigin,
dateOfBirth = dateOfBirth,
accountActivated = false
)
registerUser(user, password)
} else {
taskResult[0] = Result.failure(Data.Builder().putString("error", "AUTHENTICATION_FAILED").build())
countDownLatch.countDown()
}
} else {
// Remove signed-in user and tell that the registration failed
Log.w(this.TAG(), "createUserWithEmail:failure", task.exception)
countDownLatch.countDown()
}
}.addOnCanceledListener {
Log.e(this.TAG(), "createUserWithEmail:cancelled")
}
// if (awaitsCountDown){
try {
countDownLatch.await()
} catch (e: InterruptedException) {
e.printStackTrace()
}
// }
val result = SettableFuture.create<Result>()
result.set(taskResult[0])
return result
}
启动并观察此工作程序的代码如下:
val inputData = Data.Builder()
.putString("username", register_username_input.value.trim().toLowerCase())
.putString("password", register_password_input.value)
.putString("emailAddress", register_email.value)
.putString("countryOfOrigin", register_country_of_origin.value)
.putString("dateOfBirth", register_date_of_birth.value)
.build()
val registerUserTask = OneTimeWorkRequest.Builder(RegisterTask::class.java)
.setInputData(inputData)
.build()
// Make sure only the earliest deployed task runs
WorkManager.getInstance().beginUniqueWork("registerUserTask",
ExistingWorkPolicy.REPLACE, registerUserTask).enqueue()
// See https://medium.com/@mfahadbuttt/work-manager-by-android-jetpack-eae1b181d0fd
WorkManager.getInstance().getWorkInfoByIdLiveData(registerUserTask.id).observeForever { workInfo ->
if (workInfo.state.isFinished) {
// State considered finished, determine which state it is
val outputData = workInfo.outputData
when (workInfo.state) {
WorkInfo.State.SUCCEEDED -> Toast.makeText(applicationContext, "An email has been sent to your account",
Toast.LENGTH_LONG).show()
else -> {
Log.i(this.TAG(), "State: ${workInfo.state}, output data $outputData")
Toast.makeText(applicationContext, "Account registration failed",
Toast.LENGTH_LONG).show()
}
}
}
}
为了能够在调用Firestore的异步调用后在同一个函数中返回结果,我使用了CountDownlatch
(基于this answer)。执行代码后,我发现OnCompleteLister
中的所有断点均未命中。
因此,代码将永远挂在countDownLatch.await()
语句上。
但是,通过在Firestore控制台中查看,我验证了该用户确实在“身份验证”选项卡中存在,这意味着应该已命中该断点。
我试图:
onCompleteLister
,并且仅在适当时才调用countDownLatch.countDown()
。我注意到在函数返回之后,断点会被命中,但是由于函数已经返回,因此更新后的result
并不会执行任何操作。我遵循in this post中描述的方法解决了我的问题。