Я использую 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
(на основе этот ответ ).После выполнения кода я заметил, что ни одна из моих точек останова в моем OnCompleteLister
не была достигнута.Таким образом, код всегда будет зависать в операторе countDownLatch.await()
.Однако, просмотрев консоль Firestore, я убедился, что пользователь действительно присутствует на вкладке «Аутентификация», что означает, что должна быть достигнута точка останова.
Я попытался:
- Изменитьнастройка приостановки точки останова для приостановки всех потоков , которая ничего не меняет
- Введите логическое значение, которое указывает, введены ли мы в
onCompleteLister
, и выполняем вызов countDownLatch.countDown()
только в случае необходимости.Я заметил, что после возврата функции точка останова делает попадание, но, поскольку функция уже вернулась, ничего не делается с обновленным result
.
Edit
Я следовал подходу, описанному в этом посте , который решил мою проблему.