2016-11-04 36 views
1

爲Android項目配置Kotlin後,我寫了一個簡單的MainActivity.kt。它呼籲改造獲得其中載有下列數據的JSON文件:Moshi的定製適配器與RxAndroid&Retrofit&Kotlin

 
{ 
    "message": "success", 
    "user": { 
     "username": "Eric" 
    } 
} 

現在我想用磨石的JSON數據轉換爲科特林的課,所以這裏有兩個班,以反映上述JSON結構:

 
class User(var username: String) 

class UserJson(var message: String, var user: User) 

而對於莫希自定義類型的適配器:

 
class UserAdapter { 
    @FromJson fun fromJson(userJson: UserJson) : User { 
     Log.d("MyLog", "message = ${userJson.message}") // = success 
     Log.d("MyLog", "user = ${userJson.user}")  // = null 

     return userJson.user 
    } 
} 

當它進入功能fromJson()userJson.message = "success"預期。但奇怪的是,userJson.usernull,應該是User(username="Eric")

我是Moshi和Kotlin的新手,我已經堅持了約10個小時的這個問題。請幫助我。謝謝你的幫助。

========================================

以下是的MainActivity.kt(僅50行)的完整代碼:

 
class MainActivity : AppCompatActivity() { 

    override fun onCreate(savedInstanceState: Bundle?) { 
     super.onCreate(savedInstanceState) 
     setContentView(R.layout.activity_main) 

     // Custom Type Adapters for 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()) 
       } 
    } 
} 


// ========== For Retrofit ========== 
interface AccountService { 

    @GET("u/17350105/test.json") 
    fun signUpAnonymously() : Observable<User> 

} 


// ========== For Moshi ========== 
class User(var username: String) 

class UserJson(var message: String, var user: User) 

class UserAdapter { 

    @FromJson fun fromJson(userJson: UserJson) : User { 
     Log.d("MyLog", "message = ${userJson.message}")  // = success 
     Log.d("MyLog", "user = ${userJson.user}")    // = null 

     return userJson.user 
    } 

} 

build.gradle是:

 
compile "io.reactivex.rxjava2:rxjava:2.0.0" 
compile "io.reactivex.rxjava2:rxandroid:2.0.0" 

compile "com.android.support:appcompat-v7:25.0.0" 

compile "com.squareup.retrofit2:retrofit:2.1.0" 
compile "com.squareup.retrofit2:converter-moshi:2.1.0" 
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' 

再次感謝您。

回答

1

你可以通過改變你的代碼來做下面的事情來解決問題。

基本上在你的情況下,當UserAdapter註冊時,它告訴moshi它可以創建一個User只從UserJson對象。因此,Moshi無法識別帶關鍵字user的JSON對象。

通過添加User1(請原諒命名約定)形式的間接方式,使用JSON中的User1正確創建UserJson

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) 
    } 
} 
+0

它的工作原理,謝謝!我還有一個問題:有沒有更好的方法來實現相同的目標? (我唯一需要做的就是從原始的JSON中獲取'user'字段。) – iForests

3

如果您只需要User對象。有一個名爲Moshi-Lazy-Adapters的庫,它提供了一個@Wrapped註釋,允許指定所需對象的路徑。所有你需要做的就是相應的適配器添加到您的莫希實例和chagne服務代碼:

interface AccountService { 

    @GET("u/17350105/test.json") 
    @Wrapped("user") 
    fun signUpAnonymously() : Observable<User> 
} 

無需任何其他自定義適配器。

+0

剛剛在Moshi的GitHub頁面(#182#176#113)中看到了一些相關的問題。非常感謝您的Moshi-Lazy-Adapters! – iForests

+0

只是爲了補充答案,您應該在改進構建器中像這樣定義適配器「.addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().add(Wrapped.ADAPTER_FACTORY).build()))」。如果你需要更深的路徑「@Wrapped(path = [」a「,」b「,」c「])」 – isanjosgon