Сохранить обратный вызов при асинхронном запросе к серверу - PullRequest
0 голосов
/ 15 апреля 2019

Описание:

Пишу сервис автозаполнения для Android.Необходимые учетные данные хранятся в PWA, доступ к которому осуществляется через веб-просмотр через интерфейс Javascript.При запросе учетных данных служба отправляет packageName через WebView в JS.Как только учетные данные готовы, JS отправляет учетные данные через WebView в службу.Между тем, Служба должна сохранить обратный вызов из onFillRequest таким образом, чтобы он оставался доступным при получении учетных данных на buildResponse.

Проблема:

В настоящее время я использую переменную currentCallback для храненияПерезвоните.Не хорошее решение ИМО.Это работает для первого запроса, но когда я возвращаюсь в приложение, а затем снова на экран входа в систему, я получаю сообщение об ошибке выполнения.

Кажется, 1-й обратный вызов повторно используется, даже если он должен был быть перезаписан:

    Using Callback: android.service.autofill.FillCallback@12dea01

Попытки решения

Я пытался использовать концепцию замыкания:

private lateinit var currentCallback : (FillResponse) -> Unit

override fun onFillRequest(...) {
    ...
    currentCallback = callbackWrapper(callback)
    ...
}
 private fun buildResponse (...){
    ...  
    currentCallback(fillResponse)
    ...
}

Другие понятия, такие как сопрограммы и потоки, похоже, применимы только для двунаправленных запросов к серверу.

Также приветствуются предложения по изменению структуры кода

Ресурсы:

Соответствующий код приложения:
class FreePassAutofillService : AutofillService() {

    private lateinit var currentCallback : FillCallback

override fun onFillRequest(
        request: FillRequest,
        cancellationSignal: CancellationSignal,
        callback: FillCallback
    ) {
        // Get fields and package name
        ...

        // If no fields found, abort
        if (fields.isEmpty) {
            callback.onSuccess(null)
            return
        }


        // We are registering an observer (mMessageReceiver) to receive Intents
        ...

        //set callback for asynchronous response
        Log.d(TAG, "Setting Callback: $callback")
        currentCallback = callback
        Log.d(TAG, "Callback set to $currentCallback")

        // Fetch user data asynchronously via WebView.
        sendMessage(appName)

        // perserve fields
        currentParsedStructure = buildParsedStructure (fields)
    }

    private fun buildResponse (credentials: List<JsInterface.Credentials>){
        // Add a dataset to the response
        if (::currentParsedStructure.isInitialized && ::currentCallback.isInitialized) {
            // Create the base response
            val response = FillResponse.Builder()
            // add save information to response if we want to save the fields
            ...
            //
            for (i in 0 until credentials.size) {
                val username = credentials[i].username
                val password = credentials[i].password
                Log.d(TAG, "Username: $username, Password: $password")
                //build Dataset
                ...
            }
            val fillResponse: FillResponse = response.build()

            val callback : FillCallback = currentCallback
            Log.d(TAG, "Using Callback: $callback")
            callback.onSuccess(fillResponse)
        } else {
            //Something went wrong
        }
    }
}
1-й запрос
D/Free Pass Autofill Service:
    Package name: com.discord
    autofillable fields:{AUTOFILL_HINT_EMAIL_ADDRESS=1073741825, AUTOFILL_HINT_PASSWORD=1073741824}
    Setting Callback: android.service.autofill.FillCallback@12dea01
    Callback set to android.service.autofill.FillCallback@12dea01
D/JsInterface:
    Sending Credentials: CredentialsList(datasets=[Credentials(username=filler, password=$l|r*gNH>8N<?,Gk, url=com.discord)])
D/Free Pass Autofill Service:
    Username: filler, Password: $l|r*gNH>8N<?,Gk
    Using Callback: android.service.autofill.FillCallback@12dea01
2-й запрос
D/Free Pass Autofill Service:
    Package name: com.discord
    autofillable fields:{AUTOFILL_HINT_EMAIL_ADDRESS=1073741825, AUTOFILL_HINT_PASSWORD=1073741824}
    Setting Callback: android.service.autofill.FillCallback@b8e253d
    Callback set to android.service.autofill.FillCallback@b8e253d
D/JsInterface:
    Sending Credentials: CredentialsList(datasets=[Credentials(username=filler, password=$l|r*gNH>8N<?,Gk, url=com.discord)])
D/Free Pass Autofill Service:
    Username: filler, Password: $l|r*gNH>8N<?,Gk
    Using Callback: android.service.autofill.FillCallback@12dea01
Ошибка
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.freepass, PID: 3947
    java.lang.IllegalStateException: Already called
        at android.service.autofill.FillCallback.assertNotCalled(FillCallback.java:81)
        at android.service.autofill.FillCallback.onSuccess(FillCallback.java:48)
        at com.example.freepass.FreePassAutofillService.buildResponse(FreePassAutofillService.kt:117)
        at com.example.freepass.FreePassAutofillService.access$buildResponse(FreePassAutofillService.kt:21)
        at com.example.freepass.FreePassAutofillService$mMessageReceiver$1.onReceive(FreePassAutofillService.kt:301)
        at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:313)
        at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:121)
        at android.os.Handler.dispatchMessage(Handler.java:109)
        at android.os.Looper.loop(Looper.java:207)
        at android.app.ActivityThread.main(ActivityThread.java:7539)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...