Adaptador personalizado de Moshi con RxAndroid & Retrofit & Kotlin
Después de configurar Kotlin para el proyecto de Android, escribí un sencillo MainActivity.kt
. Llamó a Retrofit para get un file JSON que contenía los siguientes datos:
{ "post": "éxito", "usuario": { "nombre de usuario": "Eric" } }
Ahora quiero usar Moshi para convertir los datos JSON a la class de Kotlin, así que aquí están las dos classs para reflejar la estructura JSON anterior:
- Orden de configuration de progtwigdores en Rx
- Reaccionar a la llamada de actualización
- RXJava Ignorar error y continuar en cadena
- Método comodín de Kotlin
- Filter rxjava no funciona
Usuario de class (nombre de usuario var: String) class UserJson (var message: String, var user: User)
Y un adaptador de tipo personalizado para Moshi:
class UserAdapter { @FromJson divertido deJson (usuarioJson: UserJson): Usuario { Log.d ("MyLog", "message = $ {userJson.message}") // = éxito Log.d ("MyLog", "usuario = $ {usuarioJson.usuario}") // = nulo return userJson.user } }
Cuando entra en la function de fromJson()
, userJson.message = "success"
como se esperaba. Pero lo extraño es que userJson.user
es null
, que debería ser User(username="Eric")
.
Soy nuevo en Moshi y Kotlin, y ya me he quedado con este problema durante aproximadamente 10 horas. Por favor, ayúdame. Gracias por cualquier ayuda.
========================================
El siguiente es el código completo de MainActivity.kt
(solo 50 líneas):
class MainActivity: AppCompatActivity () { anular diversión onCreate (savedInstanceState: Bundle?) { super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Adaptadores de tipo personalizado para Moshi val userMoshi = Moshi.Builder (). add (UserAdapter ()). build () val retrofit = Retrofit.Builder () .baseUrl ("https://dl.dropboxusercontent.com/") .addConverterFactory (MoshiConverterFactory.create (userMoshi)) .addCallAdapterFactory (RxJava2CallAdapterFactory.create ()) .build() val accountService = retrofit.create (AccountService :: class.java) accountService.signUpAnonymously () .subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ()) .subscribe {user -> Log.d ("MyLog", user.toString ()) } } } // ========== Para Retrofit ========== interfaz AccountService { @GET ("u / 17350105 / test.json") diversión signUpAnonymously (): Observable <Usuario> } // ========== Para Moshi ========== Usuario de class (nombre de usuario var: String) class UserJson (var message: String, var user: User) class UserAdapter { @FromJson divertido deJson (usuarioJson: UserJson): Usuario { Log.d ("MyLog", "message = $ {userJson.message}") // = éxito Log.d ("MyLog", "usuario = $ {usuarioJson.usuario}") // = nulo return userJson.user } }
El build.gradle
es:
compile "io.reactivex.rxjava2: rxjava: 2.0.0" compile "io.reactivex.rxjava2: rxandroid: 2.0.0" comstackr "com.android.support:appcompat-v7:25.0.0" compile "com.squareup.retrofit2: retrofit: 2.1.0" comstack "com.squareup.retrofit2: converter-moshi: 2.1.0" comstackr 'com.jakewharton.retrofit: retrofit2-rxjava2-adapter: 1.0.0'
Gracias de nuevo.
- Formulario de inicio de session con request de repetición en rxJava y Retrofit
- Cómo burlarse del repository reactivo que devuelve Observable
- RxJava usando Kotlin - cómo sincronizar 2 methods asíncronos, refactorizar desde Java
- Extraño comportamiento de componer y ObservableTransformer en RxJava cuando el genérico pasado se extiende
- RxJava (Kotlin), Observable.amb y PublishSubject no están disparando
- Métodos generics de Kotlin y inheritance
- Implementando la búsqueda que empuja los resultados a la list tan pronto como estén disponibles usando rxJava
- Transformaciones de datos con RxJava en Kotlin
Puede resolver el problema cambiando su código para hacer algo como a continuación.
Básicamente en su caso cuando el UserAdapter
está registrado, le dice a moshi que puede crear un User
solo desde el object UserJson
. Por lo tanto, Moshi no reconoce el object JSON con el user
palabra key.
Al agregar una indirección en forma de User1
(perdón por la convención de nomenclatura), UserJson
se crea correctamente con User1
de JSON.
class User(var username: String) class User1(var username: String) // I introduced this class class UserJson(var message: String, var user: User1) // changed User to User1 class UserAdapter { @FromJson fun fromJson(userJson: UserJson): User { println("message = ${userJson.message}") println("user = ${userJson.user}") return User(userJson.user.username) } }
Si solo necesitas el object User
. Hay una biblioteca llamada Moshi-Lazy-Adapters que proporciona una anotación @Wrapped
, que permite especificar la ruta al object deseado. Todo lo que tiene que hacer es agregar el adaptador correspondiente a su instancia de moshi y cambiar el código de service a:
interface AccountService { @GET("u/17350105/test.json") @Wrapped("user") fun signUpAnonymously() : Observable<User> }
No es necesario ningún otro adaptador personalizado.