ListenableWorker startWork с асинхронным вызовом не достигает точки останова - PullRequest
0 голосов
/ 12 февраля 2019

Я использую 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

Я следовал подходу, описанному в этом посте , который решил мою проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...