java.lang.RuntimeException:无法调用无参数的公共io.reactivex.Observable()

时间:2019-11-29 13:02:44

标签: android kotlin retrofit2 rx-java2 dagger-2

您好,我目前正在准备一个带有协程的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>
}

1 个答案:

答案 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
}