在改造中从AsyncTask过渡到协程:IllegalArgumentException

时间:2019-12-02 19:58:28

标签: android retrofit2 kotlin-coroutines

在从IllegalArgumentException(之前)到AsyncTask(之后)进行最小的更改时,我不断收到错误Kotlin Coroutines。请注意,代码可以与AsyncTask一起正常工作。

注意:翻新正在调用我自己的.php脚本,该脚本返回以SimpleResultObject字符串编码的某些对象json

更改前:

改造:

@FormUrlEncoded
@POST("activity_signup.php")
fun activitySignUp(
        @Field("activity_id") activityId: Int,
        @Field("user_id") userId: Int) : Call<SimpleResultObject> 

活动(在AsyncTask内部):

@Override
protected doInBackground(...) {

        val gson = GsonBuilder().setLenient().create()
            val retrofit = Retrofit.Builder()
                    .baseUrl(LOCALHOST_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build()

            val service = retrofit.create(RetrofitAPI::class.java)
            val call = service.activitySignUp(activity_id, userId)
            call.enqueue(Callback<SimpleResultObject>() {}

通过@onResponse方法接收对象,然后通常继续进行。

更改后:

改造:

 @FormUrlEncoded
 @POST("activity_signup.php")
 suspend fun activitySignUp(
            @Field("activity_id") activityId: Int,
            @Field("user_id") userId: Int): SimpleResultObject

活动:

 fun signUp() {
        myActivityScope.launch(Dispatchers.Main) {

            val gson = GsonBuilder().setLenient().create()
            val retrofit = Retrofit.Builder()
                    .baseUrl(LOCALHOST_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build()

            val service = retrofit.create(RetrofitAPI::class.java)
            try {
                val result = service.activitySignUp(specificResultObject.activityId, userId)
                } catch (t:Throwable)

java.lang.IllegalArgumentException: No Retrofit annotation found. (parameter #3) for method RetrofitAPI.activitySignUp投向service.activitySignUp线路呼叫

请注意:myActivityScope是在托管活动完成时完成的服装CoroutineScope

我已经尽我所能记住的一切:添加OkHttpClient,更改为MoshiConverterFactory,尝试其他CoroutineScope和Dispatchers,...

编辑:问题可能是由于.php在我的Exeption端而引起的,var top = $(this).offset().top - nav_height, 超出了我的参数编号(结果可能为空)?现在。

2 个答案:

答案 0 :(得分:1)

基于对问题的回答,我对代码进行了一些修改,并设法解决了该问题。正如@Mohammad Sianaki指出的,最重要的是将Retrofit版本从25.0.0提升到了26.0.0,从而解决了问题

因此,对于可能在参数编号上方的参数中获得IllegalArgumentException的其他所有人-考虑检查翻新版本

特别感谢所有提供帮助的人,尤其是@CommonsWare!

答案 1 :(得分:0)

所提供的代码有一些结构性问题。

首先,似乎正在为每个API调用创建一个改造对象。因此,应为应用程序的所有API调用之一。

第二,网络操作应在非主线程中执行。对于协程,应该在非主要上下文中调用它们,例如Dispatchers.IO

第三,我认为您应该在API函数中返回Response<SimpleResultObject>而不是SimpleResultObject

上面假设,我写了一些代码来解决这个问题。因为我认为问题信息中存在一些隐藏因素。

build.gradle

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.6.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.1'

    implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.1'
    implementation 'com.squareup.okhttp3:okhttp:3.14.1'
}

RetrofitAPI.kt

import retrofit2.Response
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST

interface RetrofitAPI {

    @FormUrlEncoded
    @POST("activity_signup.php")
    suspend fun activitySignUp(
        @Field("activity_id") activityId: Int,
        @Field("user_id") userId: Int
    ): Response<SimpleResultObject>

    // Other api declarations ...

}

BaseApiManager.kt

import okhttp3.JavaNetCookieJar
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.net.CookieManager
import java.util.concurrent.TimeUnit

abstract class BaseApiManager(endPoint: String) {

    protected val retrofitAPI: RetrofitAPI =
        createAdapter(endPoint)
            .create(RetrofitAPI::class.java)

    private fun createAdapter(choice: String): Retrofit {
        return Retrofit.Builder()
            .baseUrl(choice)
            .client(createHttpClient())
            .addConverterFactory(GsonConverterFactory.create()).build()
    }

    companion object {

        private fun createHttpClient(): OkHttpClient {
            val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
            val cookieHandler = CookieManager()
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BODY
            httpClient.interceptors().add(interceptor)

            httpClient.cookieJar(JavaNetCookieJar(cookieHandler))
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)

            return httpClient.build()
        }
    }

}

ApiManager.kt

private const val API_END_POINT = "https://your.webservice.endpoint/"

object ApiManager : BaseApiManager(API_END_POINT) {

    suspend fun activitySignUp(
        activityId: Int,
        userId: Int
    ) = retrofitAPI.activitySignUp(activityId, userId)

    // Other api implementations ...

}


用法:

fun signUp() {
    myActivityScope.launch(Dispatchers.IO) {
        ApiManager.activitySignUp(activityId, userId).also { response ->
            when {
                response.isSuccessful -> {
                    val result = response.body()
                    result?.apply {

                        // do something with the result
                    }
                }
                else -> {
                    val code = response.code()
                    val message = response.message()

                    // do something with the error parameters...
                }
            }
        }
    }
}