您好,我目前正在准备一个带有协程的MVVM的简单演示示例,并且我面临以下问题。请查看代码以及代码有什么问题。
df <- data.frame(hhm1q001 = "blue", hhm2q001 = "red", hhm1q002 = 30, hhm2q002= 50 )
df %>%
mutate(id = row_number()) %>%
reshape2::melt(id.vars = "id") %>%
tidyr::separate(variable, into = c("hhm", "q00"), sep = 4) %>%
tidyr::separate(hhm, into = c("prefix", "hhm"), sep = 3) %>%
select(-prefix, -id) %>%
reshape2::dcast(hhm ~ q00)
依赖性配置
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.mvvmcoroutine.development, PID: 18974
java.lang.RuntimeException: Failed to invoke public io.reactivex.Observable() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:113)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:225)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:121)
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: java.lang.InstantiationException: Can't instantiate abstract class io.reactivex.Observable
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:110)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:225)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:121)
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
应用代码如下
@ApplicationClass
'rxJavaVersion' : 'io.reactivex.rxjava2:rxjava:2.1.15'
'rxAndroidVersion' : 'io.reactivex.rxjava2:rxandroid:2.1.1'
'rxKotlinVersion' : 'io.reactivex.rxjava2:rxkotlin:2.4.0'
'gsonVersion' : 'com.google.code.gson:gson:2.8.2'
'retrofitVersion' : 'com.squareup.retrofit2:retrofit:2.6.2'
: 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'
: 'com.squareup.retrofit2:converter-gson:2.6.2'
: 'com.squareup.retrofit2:converter-scalars:2.6.2'
'daggerVersion' : 'com.google.dagger:dagger:2.23.2'
: 'com.google.dagger:dagger-android-support:2.23.2'
: 'com.google.dagger:dagger-compiler:2.23.2'
: 'com.google.dagger:dagger-android-processor:2.23.2'
'assistedInjectVersion' : 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.2'
: 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.2'
'okHttpVersion' : 'com.squareup.okhttp3:okhttp:4.2.0'
: 'com.squareup.okhttp3:logging-interceptor:4.2.0'
@AppComponentInterface
open class App : MultiDexApplication(), Application.ActivityLifecycleCallbacks, HasActivityInjector {
private var runningActivityCount: Int = 0
@Inject
lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector(): AndroidInjector<Activity> {
return activityDispatchingAndroidInjector
}
override fun onActivityPaused(p0: Activity) {}
override fun onActivityStarted(p0: Activity) {}
override fun onActivityDestroyed(p0: Activity) {
runningActivityCount -= 1
if (runningActivityCount == 0)
Timber.d("Application :: onActivityDestroyed()")
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {}
override fun onActivityStopped(p0: Activity) {}
override fun onActivityCreated(p0: Activity, p1: Bundle?) {
runningActivityCount += 1
}
override fun onActivityResumed(p0: Activity) {}
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this)
}
}
@ActivityBuilder
@Singleton
@Component(
modules = [
(AndroidInjectionModule::class),
(ActivityBuilder::class),
(ApplicationModule::class),
(APIModule::class),
(RepositoryModule::class),
(PostScreenModule::class)
]
)
interface AppComponent {
fun inject(app: App)
@Component.Builder
interface Builder {
@BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
}
@ApplicaitonModule
@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = [(PostScreenModule::class)])
internal abstract fun bindPostScreen(): PostScreen
}
@APIModule
@Module
class ApplicationModule {
@Provides
@Singleton
internal fun provideContext(application: Application): Context {
return application
}
@Provides
@Singleton
internal fun provideCommonPreference(context: Context): CommonPreferences {
return CommonPreferences(context)
}
}
@HeaderInterceptorClass
@Module
class APIModule {
@Provides
@Singleton
internal fun provideHeaderInterceptor(mContext: Context): HeaderInterceptor {
return HeaderInterceptor(mContext)
}
@Provides
@Singleton
internal fun provideOkHttp(mContext: Context): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(HeaderInterceptor(mContext))
.addInterceptor(interceptor)
.build()
}
@Provides
@Singleton
internal fun provideGsonConverterFactory(): GsonConverterFactory {
return GsonConverterFactory.create()
}
@Provides
@Singleton
internal fun provideScalarsConverterFactory(): ScalarsConverterFactory {
return ScalarsConverterFactory.create()
}
@Provides
@Singleton
internal fun provideRxJava2CallAdapterFactory(): RxJava2CallAdapterFactory {
return RxJava2CallAdapterFactory.createAsync()
}
@Provides
@Singleton
internal fun provideRetrofit(
okHttpClient: OkHttpClient,
gsonConverterFactory: GsonConverterFactory,
scalarsConverterFactory: ScalarsConverterFactory,
rxJava2CallAdapterFactory: RxJava2CallAdapterFactory
): Retrofit {
return Retrofit.Builder()
.addConverterFactory(gsonConverterFactory)
.addConverterFactory(scalarsConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.client(okHttpClient)
.baseUrl("https://jsonplaceholder.typicode.com")
.build()
}
@Provides
@Singleton
internal fun provideAPIUrls(retrofit: Retrofit): APIUrls {
return retrofit.create(APIUrls::class.java)
}
}
@RepositoryModule
class HeaderInterceptor @Inject constructor(private val mContext: Context) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val token = CommonPreferences(mContext).token
val request: Request
if (token.isNotEmpty()) {
val androidDeviceId = CommonPreferences(mContext).deviceUniqueId
val appVersion = BuildConfig.VERSION_NAME
val buildVersion = BuildConfig.VERSION_CODE
var lastSyncDate = "2019-11-29 12:00:00"
if (CommonPreferences(mContext).lastSyncTime.isNotEmpty()) {
lastSyncDate = CommonPreferences(mContext).lastSyncTime
}
request =
chain.request().newBuilder()
.addHeader(HEADER_X_ACCESS_TOKEN_KEY, token)
.addHeader(HEADER_DEVICE_MASTER_ID_KEY, androidDeviceId)
.addHeader(HEADER_DEVICE_ID_KEY, androidDeviceId)
.addHeader(HEADER_DEVICE_NAME_KEY, getDeviceName())
.addHeader(HEADER_DEVICE_TYPE_KEY, HEADER_DEVICE_TYPE_VALUE)
.addHeader(HEADER_PUSH_REGISTRATION_ID_KEY, token)
.addHeader(HEADER_APP_VERSION_KEY, appVersion)
.addHeader(HEADER_API_VERSION_KEY, HEADER_API_VERSION_VALUE)
.addHeader(HEADER_OS_VERSION_KEY, android.os.Build.VERSION.RELEASE)
.addHeader(HEADER_USER_ID_KEY, CommonPreferences(mContext).userId)
.addHeader(HEADER_SYNC_DATE_KEY, lastSyncDate)
.addHeader(HEADER_BUILD_VERSION, buildVersion.toString())
.build()
return chain.proceed(request)
}
return chain.proceed(chain.request())
}
}
@PostScreenModule
@Module
class RepositoryModule {
@Provides
@Singleton
internal fun provideAuthRepository(apiUrls: APIUrls): PostRepository {
return PostRepository(apiUrls)
}
}
@PostScreenActivity
@Module
class PostScreenModule {
@Provides
internal fun providePostViewModel(
application: Application,
postRepository: PostRepository
): PostViewModel {
return PostViewModel(application, postRepository)
}
}
@PostScreenViewModel
class PostScreen : BaseActivity<ActivityPostScreenBinding, PostViewModel>() {
@Inject
lateinit var mPostViewModel: PostViewModel
override fun getLayoutId(): Int = R.layout.activity_post_screen
override fun getBindingVariable(): Int = BR.viewModel
override fun getViewModel(): PostViewModel = mPostViewModel
override fun initialization() {
mPostViewModel.viewModelScope.launch(Dispatchers.Main) {
mPostViewModel.postProcess()
}
}
}
@PostRepositoryClass
class PostViewModel @Inject constructor(
application: Application,
val postRepository: PostRepository
) : BaseViewModel(application, postRepository) {
var loading = MutableLiveData<Boolean>()
init {
loading.value = false
}
suspend fun postProcess() {
withContext(Dispatchers.IO) {
postRepository.getPostData()
}
}
}
@APIUrlsInterface
@Singleton
class PostRepository @Inject constructor(private val apiUrls: APIUrls) {
@SuppressLint("CheckResult")
suspend fun getPostData() {
apiUrls.getData("https://jsonplaceholder.typicode.com/posts/1")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ data ->
println("DATA RECEIVED ::: $data")
}, { e ->
Timber.d("Exception :: ${e.message}")
})
}
@PostResponseModel
@Singleton
interface APIUrls {
@GET
suspend fun getData(@Url url: String): Observable<PostResponse>
}
答案 0 :(得分:0)
原来的问题是接口方法既为suspend
也为Observable
。 Retrofit将suspend
放在优先级,并认为返回类型应为Observable
,但是Observable
不是可序列化的数据容器。
解决方案是删除suspend
或解包API调用的数据类型:
@Singleton
interface APIUrls {
@GET
fun getData(@Url url: String): Observable<PostResponse>
// or
suspend fun getData(@Url url: String): PostResponse
}