如何在Kotlin中通过改造来处理HTTP响应中的空数组

时间:2018-07-31 15:30:47

标签: android kotlin retrofit2

我对科特林和观察员是陌生的。我正在使用Retrofit进行API调用。我的API调用以空数组形式返回响应。我无法弄清楚如何使用观察者来处理它。拜托,任何人,请帮帮我。预先感谢

API调用方法:

@GET("transaction/get")
fun getTransactions(@Query("date") date: String?, @Query("user_id") user_id: Int, @Query("account_id") account_id: Int?): Observable<TransactionModel>

连接类

public class ApiServiceNetwork private constructor()//hide the public constructor
    : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val builder: Request.Builder
        builder = request.newBuilder()
        val request1 = builder.build()
        //Here we can modify request1 and response if we want (like adding header or auth)
        val response = chain.proceed(request1)

        return response
    }

    private val logger: okhttp3.logging.HttpLoggingInterceptor
        get() {
            val logging = okhttp3.logging.HttpLoggingInterceptor()
            logging.level = okhttp3.logging.HttpLoggingInterceptor.Level.HEADERS
            logging.level = okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
            logging.level = okhttp3.logging.HttpLoggingInterceptor.Level.BODY
            return logging
        }

    fun getNetworkService(): WebServiceInterface {
        return createRetrofitInstance(EndPoint.SERVER_ENDPOINT).create(WebServiceInterface::class.java)
    }

    private fun createRetrofitInstance(url: String): Retrofit {
        val okHttpClient = OkHttpClient.Builder()
        okHttpClient.addInterceptor(this)
        okHttpClient.addNetworkInterceptor(StethoInterceptor())
        okHttpClient.addInterceptor(logger)
        retrofit.baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().setLenient().create()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(okHttpClient.connectTimeout(60,
                        TimeUnit.SECONDS).writeTimeout(60,
                        TimeUnit.SECONDS).readTimeout(60,
                        TimeUnit.SECONDS).build())
        return retrofit.build()

    }

    companion object {
        private val retrofit = Retrofit.Builder()

        fun getInstance(): ApiServiceNetwork {
            return ApiServiceNetwork()
        }
    }

我的活动中的函数调用:

mApiServiceNetwork.getNetworkService().getTransactions(date, user_id, account_id)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({

                    this.transaction = it

                    this.expenseDataAdapter.setExpenses(it.expenses!!)
                    this.recyclerView.adapter = expenseDataAdapter

                    this.textViewSpendingAccount.text = it.account!!.title

                    this.textViewSpendingExpense.text = it.total_expense.toString()
                    this.textViewSpendingIncome.text = it.total_income.toString()
                    this.textViewSpendingBalance.text = it.balance.toString()

                    Log.d("__EXPENSE", it.total_expense.toString())

                }, {
                    Toast.makeText(this.requireContext(), it.message, Toast.LENGTH_LONG).show()
                }, {
                    this.expenseDataAdapter.notifyDataSetChanged()
                })

1 个答案:

答案 0 :(得分:0)

  1. 如果您从不关心响应中的数据(即,如果它始终是一个空数组),则可以使用Completable而不是Observable<TransactionModel>。查看您的代码,情况似乎并非如此。

  2. 如果响应有时包含数据,有时返回空数组,则可以使用自定义Converter.Factory截获GSON转换器工厂之前的调用,并以所需的方式格式化返回值。这将空响应限制为您可以接受的呼叫。

带有伪代码的示例:

class EmptyArrayConverterFactory : Converter.Factory() {

    override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? {
        val delegate = retrofit.nextResponseBodyConverter<Any>(this, type, annotations)
        return Converter<ResponseBody, Any> { body ->
            var bodyString = body.String()
            if (bodyString == "{[]}") { // Or whatever the empty array is returned as
                bodyString = //Convert body string to empty/error TransactionModel JSON
            }
            delegate.convert(bodyString) 
        }
    }

}
  1. 另一种选择,如果响应有时包含数据而有时没有数据,则可以返回Observable<ResponseBody>而不是Observable<TransactionModel>,然后在subscribe()函数中自行解析响应,同时考虑到空数组的可能性。考虑到情况和我对您情况的有限了解,我认为这将是最灵活的选择。

这看起来像这样:

API定义:     @GET(“交易/获取”)     fun getTransactions(@Query(“ date”)date:字符串?,@Query(“ user_id”)user_id:Int,@Query(“ account_id”)account_id:Int?):可观察

用法:

mApiServiceNetwork.getNetworkService().getTransactions(date, user_id, account_id)
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.computation())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ responseBody ->

                if(responseBody.string() == "{[]}"){
                    // handle the empty list however you want
                }
                else{ 
                    // Handle the response normally
                    this.transaction = it

                    this.expenseDataAdapter.setExpenses(it.expenses!!)
                    this.recyclerView.adapter = expenseDataAdapter

                    this.textViewSpendingAccount.text = it.account!!.title

                    this.textViewSpendingExpense.text = it.total_expense.toString()
                    this.textViewSpendingIncome.text = it.total_income.toString()
                    this.textViewSpendingBalance.text = it.balance.toString()

                    Log.d("__EXPENSE", it.total_expense.toString())
                }

            }, {
                Toast.makeText(this.requireContext(), it.message, Toast.LENGTH_LONG).show()
            }, {
                this.expenseDataAdapter.notifyDataSetChanged()
            })