我目前正在尝试更多地利用 kotlin 协程。但我面临一个问题:在这些协程中使用 moshi 或 okhttp 时,我收到警告:
“不适当的阻塞方法调用”
解决这些问题的最佳方法是什么?我真的不想不合适;-)
我决定是否使用方形或Gson的Moshi来序列化和反序列化模型数据.
我总是不喜欢Gson的一件事是我认为它使用的反射在Android上可能很慢?莫希也使用反射吗?
moshi vs Gson的优点和缺点是什么?
我觉得它们很相似.以此语句为例,创建一个typeAdapter:
class CardAdapter {
@ToJson String toJson(Card card) {
return card.rank + card.suit.name().substring(0, 1);
}
@FromJson Card fromJson(String card) {
if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
char rank = card.charAt(0);
switch (card.charAt(1)) {
case 'C': return new Card(rank, Suit.CLUBS);
case 'D': return new Card(rank, Suit.DIAMONDS);
case 'H': return new Card(rank, Suit.HEARTS);
case 'S': return new Card(rank, Suit.SPADES);
default: throw new JsonDataException("unknown suit: " + card);
} …Run Code Online (Sandbox Code Playgroud) 我有一个User类.还有两个子类.父母和孩子.我使用{"user":"..."}从我的服务器获取json,需要根据user.type将其转换为父级或子级.
据我所知,我需要以这种方式添加自定义转换器:
Moshi moshi = new Moshi.Builder()
.add(new UserAdapter())
.build();
Run Code Online (Sandbox Code Playgroud)
这是我对UserAdapter的实现.我知道它是假的,但它甚至不能这样工作:
public class UserAdapter {
@FromJson
User fromJson(String userJson) {
Moshi moshi = new Moshi.Builder().build();
try {
JSONObject jsonObject = new JSONObject(userJson);
String accountType = jsonObject.getString("type");
switch (accountType) {
case "Child":
JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class);
return childJsonAdapter.fromJson(userJson);
case "Parent":
JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class);
return parentJsonAdapter.fromJson(userJson);
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return null;
}
@ToJson
String toJson(User user) {
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<User> jsonAdapter …Run Code Online (Sandbox Code Playgroud) 升级到Moshi 1.9.1(从1.8.0 开始)后,我遇到了以下崩溃和堆栈跟踪:
java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.garpr.android.data.models.RankedPlayer. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact.
for class com.garpr.android.data.models.RankedPlayer
for class com.garpr.android.data.models.AbsPlayer
at com.squareup.moshi.Moshi$LookupChain.exceptionWithLookupStack(Moshi.java:349)
at com.squareup.moshi.Moshi.adapter(Moshi.java:150)
at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
at com.squareup.moshi.AdapterMethodsFactory$AdapterMethod.bind(AdapterMethodsFactory.java:313)
at com.squareup.moshi.AdapterMethodsFactory.create(AdapterMethodsFactory.java:62)
at com.squareup.moshi.Moshi.adapter(Moshi.java:138)
at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
at com.squareup.moshi.Moshi.adapter(Moshi.java:72)
at com.garpr.android.data.converters.AbsPlayerConverterTest.setUp(AbsPlayerConverterTest.kt:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) …Run Code Online (Sandbox Code Playgroud) 我最近升级到 Android Studio Flamingo 和 AGP 8.0
我的生产版本启用了 minfiy 和 ShrinkResources,不允许改造进行调用。这是抛出的错误。
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:46)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202)
at retrofit2.Retrofit$1.invoke(Retrofit.java:160)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy11.checkIfEmailExists(Unknown Source)
at com.iku.data.network.service.IkuApiService$DefaultImpls.checkIfEmailExists$default(IkuApiService.kt:123)
at com.iku.auth.data.network.repository.AuthRepositoryImpl$checkEmail$2.invokeSuspend(AuthRepositoryImpl.kt:24)
at com.iku.auth.data.network.repository.AuthRepositoryImpl$checkEmail$2.invoke(AuthRepositoryImpl.kt:0)
at com.iku.auth.data.network.repository.AuthRepositoryImpl$checkEmail$2.invoke(AuthRepositoryImpl.kt:0)
at com.iku.data.network.helper.NetworkHelperKt$safeApiCall$2.invokeSuspend(NetworkHelper.kt:27)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Run Code Online (Sandbox Code Playgroud)
我在 retorfit 的 github 上发现了这个问题 - https://github.com/square/retrofit/issues/3751。并添加了新规则已在这里评论 - https://github.com/square/retrofit/issues/3751#issuecomment-1192043644
# Keep generic signature of Call, Response (R8 full mode strips signatures from …Run Code Online (Sandbox Code Playgroud) 我想知道在使用Moshi时如何忽略Kotlin类字段.
我找到了这个Java(Moshi忽略字段)的答案,它表明使用关键字transient如下
private transient String your_variable_name;
Run Code Online (Sandbox Code Playgroud)
但我找不到在Kotlin完成这项工作的正确方法.
所以我试图使用Moshi从我的服务器解析一个调用.这是我的回复对象.
public class TokenResponse {
@SerializedName("accessToken")
public String accessToken;
public String token_type;
public int expires_in;
public String userName;
public String name;
@SerializedName(".issued")
public String issued;
@SerializedName(".expires")
public String expires;
public String Roles;
}
Run Code Online (Sandbox Code Playgroud)
这是我的端点定义(不是很重要,但无论如何我都会包含它)
public interface ServerService {
@POST("/token")
@FormUrlEncoded
Call<TokenResponse> getToken(@Field("username") String username,
@Field("password") String password, @Field("grant_type") String grant_type);
}
Run Code Online (Sandbox Code Playgroud)
这是我用来调用的代码.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://xxx/")
.addConverterFactory(MoshiConverterFactory.create())
.build();
ServerService service = retrofit.create(ServerService.class);
Call<TokenResponse> call = service.getToken("admin@admin.com", "password1!", "password");
call.enqueue(new Callback<TokenResponse>() {
@Override
public void onResponse(Call<TokenResponse> call, Response<TokenResponse> response) …Run Code Online (Sandbox Code Playgroud) 我最近开始在我的 Android 应用程序中使用 Moshi,我很想知道更多关于注释的@JsonClass(generateAdapter = true) 真正作用。
示例数据类:
data class Person(
val name: String
)
Run Code Online (Sandbox Code Playgroud)
我可以按如下方式序列化/反序列化这个类:
val moshi: Moshi = Moshi.Builder().build()
moshi.adapter(Person::class.java).toJson(Person())
Run Code Online (Sandbox Code Playgroud)
我在这里没有使用 @JsonClass 注释,因此不会启动代码生成。
我的问题是,为什么以及何时需要使用 @JsonClass(generateAdapter = true)
有没有办法反序列化json使用
sealed class Layer
data class ShapeLayer(var type: LayerType) : Layer
data class TextLayer(var type: LayerType) : Layer
data class ImageLayer(var type: LayerType) : Layer
Run Code Online (Sandbox Code Playgroud)
LayerType只是一些枚举,可用于区分此对象应具有的类型.
我以为我可以这样添加适配器:
class LayerAdapter{
@FromJson
fun fromJson(layerJson: LayerJson): Layer {
return when (layerJson.layerType) {
LayerType.SHAPE -> PreCompLayer()
LayerType.SOLID -> SolidLayer()
LayerType.Text -> TextLayer()
}
}
}
Run Code Online (Sandbox Code Playgroud)
其中LayerJson将是具有所有LayerTypes的所有可能字段的对象.
现在的问题是:
无法序列化抽象类com.example.models.layers.Layer
我可以尝试使用接口,但我不认为在这里使用空接口是正确的.
当我在字段中使用@Json时,序列化不会正确发生,但它在更改为@field:Json后开始工作。
我在阅读了一些错误线程后经历了这个变化,我认为这是 kotlin 特有的。我想知道 @field:Json 带来什么区别,它真的特定于 kotlin 吗?