Обработка обратного вызова с помощью Kotlin - PullRequest
0 голосов
/ 27 ноября 2018

Возможно, это очень простая тема, но я не могу найти правильный ответ.

Это сделка, я использовал эту логику для обработки API в моем текущем проекте Android:

  • класс SampleApi

  • интерфейс ISampleApi

  • интерфейс SampleClient

  • класс GetUserData

Теперь, когда я переезжаю в Котлин, я не могу скопировать функцию enqueue() из модернизации в мой класс Api.Это пример моего кода:

GetUserData.java:

class GetUserData {
private void tryGetData() {
    sampleApi.getSomeData(userId, new Callback<Data>() {
        @Override
        public void onResponse(final Call<Data> call, final Response<Data> response) {
            ......Do Something
        }

        @Override
        public void onFailure(final Call<Data> call, final Throwable t) {
            ......Do Something
        }
    });

Я использую интерфейс для объявления методов, которые будут реализованы в классе API:

public interface ISampleApi {

void getSomeData(@NonNull String userId,
                     @NonNull Callback<Data> callback);

}

Это мой класс API:

public class SampleApi implements ISampleApi {
............
  @Override
  public void getSomeData(@NonNull final String userId,
                            @NonNull final Callback<Data> callback) {
    myClient.getSomeData(userId).enqueue(callback);
  }
}

А это MyClient с использованием Retrofit:

public interface SampleClient {
  @GET("user/data/{userId}")
  Call<Data> getSomeData(@NonNull @Path("userId") String userId);
}

Весь код выше работает нормально, это то, что я используюв моем приложении без проблем.

Теперь, это проблема при переходе на Kotlin, я пытаюсь создать обратный вызов enqueue в SampleApi, и мне нужно вернуть ответ классу, где был создан обратный вызов,в Kotlin должно быть что-то вроде этого:

fun getSomeData(userId: String, callback: CallBack<Data>) {
  client?.getSomeData(userId).enqueue(callback)
}

Но при попытке сделать это, Android Studio говорит мне, что я должен создать функцию расширения, я создаю функцию расширения, и после большего предложения от Android Studioи некоторые исследования показывают, что результат выглядит примерно так:

override fun getSomeData(@NonNull userId: String,
                             @NonNull callback: Callback<Data>) {//Neve using this callback
    client?.getSomeData(userId).enqueue {
      success = {
       success -> Do Something
      }
      failure = {
        failure -> Do Something
      }
    }
}

fun<T> Call<T>.enqueue(callback: BaseCallback<T>.() -> Unit) {
    val callbackBk = BaseCallback<T>()
    callback.invoke(callbackBk)
    this.enqueue(callbackBk)

}

class BaseCallback<T>: Callback<T> {
    var success: ((Response<T>) -> Unit)? = null
    var failure: ((t: Throwable?) -> Unit)? = null

    override fun onFailure(call: Call<T>, t: Throwable) {
        failure?.invoke(t)
    }

    override fun onResponse(call: Call<T>, response: Response<T>) {
        success?.invoke(response)
    }
}

BaseCallback.kt

open class BaseCallback<T: Validatable>(): Callback<BaseResponseBody<T>> {
var success: ((T) -> Unit)? = null
var failure: ((networkingError: NetworkingError?) -> Unit)? = null
override fun onResponse(call: Call<BaseResponseBody<T>>, response: Response<BaseResponseBody<T>>) {

    if (response?.code() != null
            && response.isSuccessful
            && response.body() != null
            && response.body().containsValidSuccess()) run {

        onSuccessfulResponse(response.body().data!!)
    } else if (response != null
            && response.isSuccessful
            && response.body() != null) {

        onSuccessfulResponse()
    } else {
        onNonSessionErrorEncountered(networkingError)
    }
}

override fun onFailure(call: Call<BaseResponseBody<T>>, throwable: Throwable) {
    onNonSessionErrorEncountered(NetworkStateError(throwable))
}

@VisibleForTesting(otherwise = PROTECTED)
fun onSuccessfulResponse(responseValue: T) {
    success?.invoke(responseValue)
}

@VisibleForTesting(otherwise = PROTECTED)
fun onSuccessfulResponse() {
    // This method intentionally left blank.
}

fun onSessionErrorEncountered() {
    // This method intentionally left blank.
}

@VisibleForTesting(otherwise = PROTECTED)
fun onNonSessionErrorEncountered(networkingError: NetworkingError) {
    failure?.invoke(networkingError)
}
}

Этот код работает нормально, я могу получать данные, но мне нужно получить ответвнутри классакоторый вызывает эту конечную точку, так как мне нужно изменить пользовательский интерфейс.

Я очень ценю некоторую помощь, я застрял с этим некоторое время, и мне нужно решить проблему, чтобы продолжить работу с приложением.

1 Ответ

0 голосов
/ 27 ноября 2018

Поместите ниже код в файл AppRepository.kt

companion object { 

fun getServiceDetails(map: Map<String, String>, callback: ApiCallback<ServiceDetailsDataClass.ServiceDetailsResponse>) {
        val retrofit = ApiClient.retrofit
        val callGet = retrofit?.create<ApiService.ServiceDetails>(ApiService.ServiceDetails::class.java)?.getServiceDetails(map, ApiConstants.API_KEY, ApiConstants.API_LANG)

        callGet?.enqueue(object : Callback<ServiceDetailsDataClass.ServiceDetailsResponse> {
            override fun onFailure(call: Call<ServiceDetailsDataClass.ServiceDetailsResponse>?, t: Throwable?) {
                callback.onError(t.toString())
            }

            override fun onResponse(call: Call<ServiceDetailsDataClass.ServiceDetailsResponse>?, response: Response<ServiceDetailsDataClass.ServiceDetailsResponse>?) {
                if (response?.isSuccessful!!) {
                    callback.onSuccess(response.body()!!)
                } else {
                    setError(callback, response)
                }
            }

        })
    }

Файл интерфейса ApiCallBack.kt имеет код:

interface ApiCallback<T> {
fun onException(error: Throwable)

fun onError(error: String)

fun onSuccess(t: T)

}

Файл ApiService.kt имееткод:

 interface ApiService {

interface ServiceDetails {
    @GET("api/path/here/")
    fun getServiceDetails(@QueryMap map: Map<String, String>, @Header(ApiConstants.KEY_X_API) apiKey: String, @Header(ApiConstants.KEY_ACCEPT_LANGUAGE) language: String): Call<ServiceDetailsDataClass.ServiceDetailsResponse>
}

Теперь вызовите API, используя:

AppRepository.getServiceDetails(map, object : ApiCallback<ServiceDetailsDataClass.ServiceDetailsResponse> {
        override fun onException(error: Throwable) {
            serviceDetailsResponse.value = error
        }

        override fun onError(error: String) {
            serviceDetailsResponse.value = error
        }

        override fun onSuccess(t: ServiceDetailsDataClass.ServiceDetailsResponse) {
            serviceDetailsResponse.value = t

        }

    })

Надеюсь, это поможет вам.

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