首页 > 解决方案 > 使用 MVP 对 Kotlin 进行改造的 Api 调用问题

问题描述

我正在使用 MVP 中的 Retrofit 与 kotlin 合作。API 不返回响应或完成视图加载。

演示者代码

import android.content.Context
import android.util.Log
import com.crosspoles.CrosspolesApp
import com.crosspoles.R
import com.crosspoles.Views.LoginView

import com.ruhe.model.LoginModel

import okhttp3.RequestBody

import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
class LoginPresenter : BasePresenter<LoginView?>() {

    fun LoginUser(activity:Context, map:HashMap<String, RequestBody>, progress:Boolean) {
        
        view!!.enableLoadingBar(activity, progress, activity.getResources().getString(R.string.loading))
        CrosspolesApp.instance
                ?.apiService

                ?.login(map).enqueue(object:Callback<LoginModel> {
                    override fun onResponse(call:Call<LoginModel>, response:Response<LoginModel>) {
                        view!!.enableLoadingBar(activity, false, "")
                        view!!.onLoginComplete(response.body(), response.code())
                        Log.e("@@Start","dsadas")
                    }
                    override fun onFailure(call:Call<LoginModel>, t:Throwable) {
                        Log.e("@@Start2","dsadas")
                        view!!.enableLoadingBar(activity, false, "")
                        try {
                            t.printStackTrace()
                        }
                        catch (e:Exception) {
                            e.printStackTrace()
                        }
                        view!!.onError(null)
                    }

                })
    }


}

private fun <T> Call<T>?.enqueue(callback: Callback<LoginModel>) {

}

API服务

package com.crosspoles.service

import com.crosspoles.model.LoginModel
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.PartMap
import java.util.*

interface ApiService {
    @Multipart
    @POST("login")
    fun login(@PartMap map: HashMap<String, RequestBody>): Call<LoginModel?>?
}

CrosspolesApp是与整个项目一起继承的应用程序调用

package com.crosspoles

import android.content.Context
import android.os.StrictMode
import androidx.multidex.MultiDex
import androidx.multidex.MultiDexApplication
import com.crosspoles.service.ApiService
import com.crosspoles.service.CustomInterceptor
import com.facebook.stetho.Stetho
import com.google.gson.GsonBuilder
import com.crosspoles.extra.Constants
import io.github.inflationx.calligraphy3.CalligraphyConfig
import io.github.inflationx.calligraphy3.CalligraphyInterceptor
import io.github.inflationx.viewpump.ViewPump
import okhttp3.Cache
import okhttp3.ConnectionPool
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.io.File
import java.util.*
import java.util.concurrent.TimeUnit

class CrosspolesApp : MultiDexApplication() {
    var isAidl = false

    var apiService: ApiService? = null
        private set
    override fun onCreate() {
        super.onCreate()
        instance = this
        MultiDex.install(applicationContext)
        createApiService()
        val builder = StrictMode.VmPolicy.Builder()
        StrictMode.setVmPolicy(builder.build())
        ViewPump.init(ViewPump.builder()
                .addInterceptor(CalligraphyInterceptor(
                        CalligraphyConfig.Builder()
                                .setDefaultFontPath("fonts/open_sans_regular.ttf")
                                .setFontAttrId(R.attr.fontPath)
                                .build()))
                .build())
        Stetho.initializeWithDefaults(this)
    }
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
    }
    fun createApiService(): ApiService? {
        val gson = GsonBuilder().create()
        val httpCacheDirectory = File(cacheDir, "cache_file")
        val cache = Cache(httpCacheDirectory, 20 * 1024 * 1024)
        val okHttpClient = OkHttpClient.Builder()
                .connectTimeout(2, TimeUnit.MINUTES)
                .writeTimeout(2, TimeUnit.MINUTES)
                .readTimeout(2, TimeUnit.MINUTES)
                .connectionPool(ConnectionPool(0, 5 * 60 * 1000, TimeUnit.SECONDS))
                .addInterceptor(CustomInterceptor(instance, Locale.getDefault().language, appVersion))
                .cache(cache)
                .build()
        val retrofit = Retrofit.Builder().client(okHttpClient)
                .baseUrl(Constants.BASE_crosspoles_URL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build()
        apiService = retrofit.create(ApiService::class.java)
        return apiService
    }
    private val appVersion: String
        private get() = try {
            packageManager.getPackageInfo(packageName, 0).versionName
        } catch (e: Exception) {
            e.printStackTrace()
            "1.1"
        }
    companion object {
        var instance: CrosspolesApp? = null
            private set
    }
}

我想知道这些有什么错误。如果需要更多了解其他代码,请通知我。

标签: javaandroidkotlinretrofit2

解决方案


根据问题下评论中的讨论以及另外发布的代码,我假设并且大部分可以肯定的是,问题是传递给enqueue函数的回调对象类型错误。

目前,入队函数接收类型为Callback<LoginModel>

CrosspolesApp.instance
             ?.apiService
             ?.login(map).enqueue(object: Callback<LoginModel> { ... })

但是根据ApiService命名的函数login返回可选Call对象和可选的 LoginModel响应对象。

这意味着调用enqueue函数的正确方法是:

CrosspolesApp.instance
             ?.apiService
             ?.login(map)?.enqueue(object: Callback<LoginModel?> { ... })

由于login(map)返回可选Call对象问号放置在调用之前enqueue

确保更新Callback对象onResponseonFailure函数实现(注意问号):

override fun onResponse(call: Call<LoginModel?>, ...) { ... }
override fun onFailure(call: Call<LoginModel?>, ...) { ... }

删除空扩展功能,因为它没有任何作用。


推荐阅读