Я пытаюсь использовать сеть с Retrofit 2.
call.enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>?, response: Response<String>?) {
Timber.d("onResponse(): ${response.toString()}")
Timber.d("onResponse() body: ${response?.body().toString()}")
Toast.makeText(this@MainActivity, response?.message(), Toast.LENGTH_SHORT).show()
var data: String? = response?.body()
val resultIntent = Intent(this@MainActivity, ProgressActivity::class.java)
resultIntent.putExtra(M_DATA, data)
startActivity(resultIntent)
finish()
}
override fun onFailure(call: Call<String>?, t: Throwable?) {
Toast.makeText(this@MainActivity, t.toString(), Toast.LENGTH_SHORT).show()
Timber.d("onFailure(): ${t.toString()}")
}
})
Это показывает ошибку, которая говорит Expected a string but was BEGIN_OBJECT
.
Итак, я попытался это:
call.enqueue(object : Callback<MData> {
override fun onResponse(call: Call<MData>?, response: Response<MData>?) {
Timber.d("onResponse(): ${response.toString()}")
Timber.d("onResponse() body: ${response?.body().toString()}")
Toast.makeText(this@MainActivity, response?.message(), Toast.LENGTH_SHORT).show()
var data: MData? = response?.body()
val resultIntent = Intent(this@MainActivity, ProgressActivity::class.java)
resultIntent.putExtra(M_DATA, data)
startActivity(resultIntent)
finish()
}
override fun onFailure(call: Call<MData>?, t: Throwable?) {
Toast.makeText(this@MainActivity, t.toString(), Toast.LENGTH_SHORT).show()
Timber.d("onFailure(): ${t.toString()}")
}
})
Теперь он показывает Expected BEGIN_OBJECT but was string
Я проверил тело ответа с помощью Any
, полученные данные верны.
Однако я не хочу использовать Any
но используйте правильный тип объекта, который MData
Я хочу использовать MData
в качестве типа ответа.Что мне делать?
Это класс ServiceGenerator
.
fun <S> createService(serviceClass: Class<S>): S? {
/**
* setLevel(): Set the log level specifying which message levels will be logged by this logger.
* 참고: https://developer.android.com/reference/java/util/logging/Logger
*
* HttpLoggingIntercepotr Levels:
* NONE: No logs.
* BASIC: Logs request and response lines.
* HEADERS: Logs request and response lines and their respective headers.
* BODY: Logs request and response lines and their respective headers and bodies (if present).
* 참고: https://square.github.io/okhttp/3.x/logging-interceptor/okhttp3/logging/HttpLoggingInterceptor.Level.html
*/
val logging = HttpLoggingInterceptor()
if (BuildConfig.DEBUG) { // If Build is Debug Mode, Show Log
logging.level = HttpLoggingInterceptor.Level.BODY //
} else { // Otherwise, show nothing.
logging.level = HttpLoggingInterceptor.Level.NONE
}
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
val gson = GsonBuilder()
.setLenient()
.create()
val retrofit: Retrofit
try {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // We can use Basic Format of Retrofit 2 & Call Adapters
.build()
return retrofit.create(serviceClass) // Retrofit creates Service with the received serviceClass.
} catch (e: Exception) {
e.printStackTrace() // Exception(Internal Error) can cause from newProxyInstance().
}
return null
}
И это мой интерфейс для Retrofit.
interface MApi {
// @Headers("Content-Type: application/x-www-form-urlencoded")
@Headers("Content-Type: application/json")
@FormUrlEncoded
@POST("/")
fun getInfo(@Field("key") key: String): Call<String>
companion object {
val BASE_URL = "http://abc.io/"
val MEDIA_TYPE_JSON = MediaType.parse("application/json")
val MEDIA_TYPE_X_WWW_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded")
}
}
MData
выглядит такэто:
class MData(var num: Int, var key: String?, var data: MDao) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readParcelable(MDao::class.java.classLoader))
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(num)
parcel.writeString(key)
parcel.writeParcelable(data, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MData> {
override fun createFromParcel(parcel: Parcel): MData {
return MData(parcel)
}
override fun newArray(size: Int): Array<MData?> {
return arrayOfNulls(size)
}
}
}
И MDao
выглядит так:
class MDao(var data: String?, var owner: String?) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString())
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(data)
parcel.writeString(owner)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MDao> {
override fun createFromParcel(parcel: Parcel): MDao {
return MDao(parcel)
}
override fun newArray(size: Int): Array<MDao?> {
return arrayOfNulls(size)
}
}
}