【问题标题】:Retrofit 2 doesn't perform a request改造 2 不执行请求
【发布时间】:2019-05-26 19:56:14
【问题描述】:

我的应用需要使用 OAuth 2.0 连接到 GitHub.com。所以我创建了下一个 API 模型:

interface IGitHubApi {
    @GET("login/oauth/access_token")
    fun getAccessToken(
        @Query("client_id") clientId: String = GitHub.CLIENT_ID,
        @Query("client_secret") clientSecret: String = GitHub.CLIENT_SECRET,
        @Query("code") code: String
    ): Single<String>
}

我知道我可以提供一个描述 JSON 结构的类,Gson 会自动反序列化它,但我想看到一个简单的 JSON(作为字符串)。 p>

在我为 Retrofit 2 创建组件和模块之后:

@Component(modules = [GitHubApiModule::class])
interface IGitHubApiComponent {
    fun getGitHubService(): IGitHubApi
}

@Module
class GitHubApiModule {

    @Provides
    fun provideGitHubApi(retrofit: Retrofit): IGitHubApi {
        return retrofit.create(IGitHubApi::class.java)
    }

    @Provides
    fun provideRetrofit(gsonConverterFactory: GsonConverterFactory,
                        rxJava2CallAdapterFactory: RxJava2CallAdapterFactory): Retrofit {
        return Retrofit.Builder()
            .baseUrl(GitHub.BASE_URL)
            .addConverterFactory(gsonConverterFactory)
            .addCallAdapterFactory(rxJava2CallAdapterFactory)
            .build()
    }

    @Provides
    fun provideGson(): Gson {
        val gsonBuilder = GsonBuilder()
        return gsonBuilder.create()
    }

    @Provides
    fun provideGsonConverterFactory(gson: Gson): GsonConverterFactory {
        return GsonConverterFactory.create(gson)
    }

    @Provides
    fun provideRxJava2CallAdapterFactory(): RxJava2CallAdapterFactory {
        return RxJava2CallAdapterFactory.create()
    }
}

并将 Dagger 2 连接到我的视图模型:

class AccountViewModel(app: Application) : AndroidViewModel(app) {

    var label: ObservableField<String> = ObservableField()
    var isLoading: ObservableBoolean = ObservableBoolean(true)
    var progress: ObservableInt = ObservableInt(0)
    private var gitHubApi: IGitHubApi = DaggerIGitHubApiComponent.create().getGitHubService()

    private fun getErrorMsg(app: Application, hasAccount: Boolean): String {
        return if (hasAccount) {
            app.getString(R.string.err_account_update_failed)
        } else {
            app.getString(R.string.err_account_creation_failed)
        }
    }

    fun createOrUpdateAccount(authorizationCode: String?) {
        val app = getApplication<App>()
        val accountType = app.getString(R.string.account_type_git)
        val accountManager = AccountManager.get(app.applicationContext)
        val accounts = accountManager.getAccountsByType(accountType)

        label.set(app.getString(R.string.msg_account_creating))

        if (authorizationCode == null) {
            val msg = getErrorMsg(app, accounts.isNotEmpty())
            label.set(msg)

            return //Break operation
        }

        gitHubApi.getAccessToken(code = authorizationCode)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeBy(
                onSuccess = {
                    label.set(it)
                    progress.set(100)
                    isLoading.set(false)
                },
                onError = {
                    Log.e("AccountViewModel", it.message?: "Could not retrieve an access token.", it)
                    val msg = getErrorMsg(app, accounts.isNotEmpty())
                    label.set(msg)
                }
            )
            .dispose()
    }
}

当我运行我的应用程序时,我只看到 Creating an account... 标签,这意味着 onSuccessonError 方法未被调用。

我做错了什么?它必须至少调用onError,并且LogCat中没有任何相关错误。

我已签入调试器应用检索授权码,它不是null

【问题讨论】:

  • 你的即时dispose()有什么意义?
  • @laalto,我需要在onSuccessonError 中调用它吗?抱歉,这是我第一个使用 RxJava 和 Dagger 的项目,我还是个菜鸟。
  • dispose() 在提交之前取消您的通话 - 我相信您根本不应该拥有它。
  • @Шах 跟踪所有一次性用品(可能使用CompositeDisposable)并在覆盖的onCleared方法中调用dispose()
  • @Шах 听起来不错。需要注意的一点,你不需要检查它是否已经被释放,你可以立即释放,因为操作是幂等的

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


【解决方案1】:

主要原因:dispose()本质上是取消,dispose后不会收到成功或错误事件。

AndroidStudio 要求调用此方法

subscribeBy() 带有 @CheckReturnValue 注释,Studio 抱怨您忽略了返回的 Disposable

对于即发即弃的请求,您可以忽略一次性并抑制 IDE 警告。

如果您想确定请求的范围并能够取消它,例如当导航到另一个屏幕时,您可以将Disposable 存储到一个变量中,并以适当的生命周期方法对其调用dispose()。如果您有多个此类请求,可以使用CompositeDisposable 将它们捆绑在一起。

在您的 cmets 中,您声明您有一个 ViewModel。在ViewModel 中,您可以覆盖onCleared() 并在那里处理调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多