Api调用问题,使用MVP架构的Kotlin中的Retrofit。

huangapple go评论86阅读模式
英文:

Api call issue with Retrofit for kotlin using MVP

问题

我正在使用 Kotlin 和 Retrofit 在 MVP 中进行工作但 API 没有返回响应或完成视图加载

**presenter 代码**

```kotlin
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 service

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
    }
}

如果您需要更详细的解释或其他代码,请告诉我。

英文:

I am working with kotlin using Retrofit in MVP. The API not return the response or finish the view load.

presenter code

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&lt;LoginView?&gt;() {
fun LoginUser(activity:Context, map:HashMap&lt;String, RequestBody&gt;, progress:Boolean) {
view!!.enableLoadingBar(activity, progress, activity.getResources().getString(R.string.loading))
CrosspolesApp.instance
?.apiService
?.login(map).enqueue(object:Callback&lt;LoginModel&gt; {
override fun onResponse(call:Call&lt;LoginModel&gt;, response:Response&lt;LoginModel&gt;) {
view!!.enableLoadingBar(activity, false, &quot;&quot;)
view!!.onLoginComplete(response.body(), response.code())
Log.e(&quot;@@Start&quot;,&quot;dsadas&quot;)
}
override fun onFailure(call:Call&lt;LoginModel&gt;, t:Throwable) {
Log.e(&quot;@@Start2&quot;,&quot;dsadas&quot;)
view!!.enableLoadingBar(activity, false, &quot;&quot;)
try {
t.printStackTrace()
}
catch (e:Exception) {
e.printStackTrace()
}
view!!.onError(null)
}
})
}
}
private fun &lt;T&gt; Call&lt;T&gt;?.enqueue(callback: Callback&lt;LoginModel&gt;) {
}

Api service

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(&quot;login&quot;)
fun login(@PartMap map: HashMap&lt;String, RequestBody&gt;): Call&lt;LoginModel?&gt;?
}

CrosspolesApp is an application call inherits with whole projects

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(&quot;fonts/open_sans_regular.ttf&quot;)
.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, &quot;cache_file&quot;)
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()
&quot;1.1&quot;
}
companion object {
var instance: CrosspolesApp? = null
private set
}
}

I want to know what mistake in these. Please notify me if any other code needed to more understand.

答案1

得分: 1

根据问题下的评论讨论以及额外发布的代码,我假设并且相当确定问题是在 enqueue 函数中传入了错误类型的回调对象。

目前,enqueue 函数接收的是 Callback<LoginModel> 类型的对象:

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

但是根据名为 loginApiService 函数返回的是可选的带有可选的 LoginModel 响应对象的 Call 对象。

这意味着调用 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?>, ...) { ... }

移除空的扩展函数,因为它没有任何用途。

英文:

According to the discussion in the comments under the question and additionally posted code I assume, and mostly sure, that the issue is the wrong type of callback object passed into the enqueue function.

Currently, the enqueue function receives object of type Callback&lt;LoginModel&gt;:

CrosspolesApp.instance
?.apiService
?.login(map).enqueue(object: Callback&lt;LoginModel&gt; { ... })

But according to ApiService function named login returns optional Call object with optional LoginModel response object.

It means that the correct way to call enqueue function would be:

CrosspolesApp.instance
?.apiService
?.login(map)?.enqueue(object: Callback&lt;LoginModel?&gt; { ... })

Since login(map) returns optional Call object question mark was placed before calling enqueue.

Make sure you update Callback object onResponse and onFailure functions implementation (note the question marks):

override fun onResponse(call: Call&lt;LoginModel?&gt;, ...) { ... }
override fun onFailure(call: Call&lt;LoginModel?&gt;, ...) { ... }

Remove the empty extension function as it serves no purpose.

huangapple
  • 本文由 发表于 2020年10月6日 14:39:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/64220565.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定