首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Single.zip()时,成功的API调用返回空值

使用Single.zip()时,成功的API调用返回空值
EN

Stack Overflow用户
提问于 2020-10-13 04:41:18
回答 1查看 96关注 0票数 0

我使用Single.zip()和Function 5将5个API调用合并为一个:

代码语言:javascript
复制
private fun loadProfileAndBalances() {


        registerSubscription(
                Single.zip<AvailableFundsResult, IncomingFundsResult, TotalEarnedResult, TotalDonatedResult, ProfileResult, Unit>(
                        Interactors.api.paymentsApiClient.getAvailableFunds()
                                .map<AvailableFundsResult> {

                                    Timber.d("Available Result [${it.amount}]") <------ DollarAmount object with null amount
                                    AvailableFundsResult.Amount(it) }
                                .onErrorReturn { AvailableFundsResult.Error(it) }
                                .scheduleIOUI(),

                        Interactors.api.paymentsApiClient.getIncomingFunds()
                                .map<IncomingFundsResult> { IncomingFundsResult.Amount(it) }
                                .onErrorReturn { IncomingFundsResult.Error(it) }
                                .scheduleIOUI(),

                        Interactors.api.paymentsApiClient.getTotalEarned()
                                .map<TotalEarnedResult> { TotalEarnedResult.Amount(it) }
                                .onErrorReturn { TotalEarnedResult.Error(it) }
                                .scheduleIOUI(),

                        Interactors.api.paymentsApiClient.getTotalDonated()
                                .map<TotalDonatedResult> { TotalDonatedResult.Amount(it) }
                                .onErrorReturn { TotalDonatedResult.Error(it) }
                                .scheduleIOUI(),

                        Interactors.profileManager.getNotCachedProfile()
                                .map<ProfileResult> { ProfileResult.Profile(it) }
                                .onErrorReturn { ProfileResult.Error(it) }
                                .scheduleIOUI(),

                        Function5 { availableFunds: AvailableFundsResult, incomingFunds: IncomingFundsResult, totalEarned: TotalEarnedResult, totalDonated: TotalDonatedResult, profileResult: ProfileResult ->

                            availableTotal = when (availableFunds) {
                                is AvailableFundsResult.Amount ->
                                    availableFunds.result.amount

                                is AvailableFundsResult.Error -> {
                                    Timber.w(availableFunds.throwable, "Error while fetching sponsorships")
                                    "0.00"
                                }
                            }

                            incomingTotal = when (incomingFunds) {
                                is IncomingFundsResult.Amount -> incomingFunds.result.amount

                                is IncomingFundsResult.Error -> {
                                    Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
                                    "0.00"
                                }
                            }

                            earnedTotal = when (totalEarned) {
                                is TotalEarnedResult.Amount -> totalEarned.result.amount

                                is TotalEarnedResult.Error -> {
                                    Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
                                    "0.00"
                                }

                            }

                            donatedTotal = when (totalDonated) {
                                is TotalDonatedResult.Amount -> totalDonated.result.amount

                                is TotalDonatedResult.Error -> {
                                    Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
                                    "0.00"
                                }

                            }

                            onboardingComplete = when (profileResult) {
                                is ProfileResult.Profile ->
                                    profileResult.result.isOnboardingCompleted


                                is ProfileResult.Error -> {
                                    Timber.e(profileResult.throwable, "Error fetching profile")
                                    true
                                }

                            }


                        }
                ).ignoreElement()
                        .subscribe(::updateViews) {
                            it.printStackTrace()
                            availableTotal = ""
                            incomingTotal = ""
                            earnedTotal = ""
                            donatedTotal = ""
                            onboardingComplete= false
                            vWalletRefresher.isRefreshing = false
                            internetConnectionError(it)
                        })


}

这些API调用中的每一个都成功地使用了代码200。使用Interactors.api.paymentsApiClient.getAvailableFunds()进行的调用将返回{"amount":264.69},并将其解析为此类的对象:

代码语言:javascript
复制
internal data class DollarAmount(@SerializedName("amount") val amount: String)

重复引用的paymentsApiClient是这样构建的:

代码语言:javascript
复制
 private fun createNewPaymentsClient(authRefreshClient: AuthRefreshClient,
                                   preferencesInteractor: PreferencesInteractor): PaymentsApiClient {

    val loggingInterceptor = run {
        val httpLoggingInterceptor = HttpLoggingInterceptor()
        httpLoggingInterceptor.apply {
            httpLoggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
        }
    }


    val okHttpClient = createHttpClientBuilder()
            .addInterceptor(createSessionRequestInterceptor())
            .addInterceptor(createUserAgentInterceptor(context))
            .addInterceptor(loggingInterceptor)
            .authenticator(RefreshUserAuthenticator(authRefreshClient, preferencesInteractor,
                    UnauthorizedNavigator(SDKInternal.appContext, Interactors.preferences)))
            .build()


    val gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().setLenient().create()

    return Retrofit.Builder()
            .client(okHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .baseUrl(Interactors.apiEndpoint)
            .build()
            .create(PaymentsApiClient::class.java)

}

尽管API调用成功,但在Single.zip中打印的用于通过Interactors.api.paymentsApiClient.getAvailableFunds()成功检索DollarAmount的日志语句显示其数量为null,而不是264.69。我的解析出了什么问题,导致它为空?

编辑:正如有人注意到的,我将结果包装在另一组类中:

代码语言:javascript
复制
   private sealed class AvailableFundsResult {
    data class Error(val throwable: Throwable) : AvailableFundsResult()
    data class Amount(val result: DollarAmount) : AvailableFundsResult()
}

private sealed class IncomingFundsResult {
    data class Error(val throwable: Throwable) : IncomingFundsResult()
    data class Amount(val result: DollarAmount) : IncomingFundsResult()
}

private sealed class TotalEarnedResult {
    data class Error(val throwable: Throwable) : TotalEarnedResult()
    data class Amount(val result: DollarAmount) : TotalEarnedResult()
}

private sealed class TotalDonatedResult {
    data class Error(val throwable: Throwable) : TotalDonatedResult()
    data class Amount(val result: DollarAmount) : TotalDonatedResult()
}

private sealed class ProfileResult {
    data class Error(val throwable: Throwable) : ProfileResult()
    data class Profile(val result: InfluencerProfileDto) : ProfileResult()
}

我不认为这是相关的,因为在我还没有吐出这些包装器类的实例之前,数量就返回了null。

编辑2:从第五次API调用返回的类:

代码语言:javascript
复制
@JsonClass(generateAdapter = true)
internal data class InfluencerProfileDto(
        @Json(name = "id") val id: String,
        @Json(name = "emailAddress") val email: String?,
        @Json(name = "phoneNumber") val phoneNumber: PhoneNumberDto?,
        @Json(name = "isPhoneNumberVerified") val isPhoneNumberVerified: Boolean,
        @Json(name = "isEmailVerified") val isEmailVerified: Boolean,
        @Json(name = "notificationTimePreference") val notificationTimePreference: String,
        @Json(name = "isInstagramConnected") val isInstagramConnected: Boolean,
        @Json(name = "isFacebookConnected") val isFacebookConnected: Boolean,
        @Json(name = "isTwitterConnected") val isTwitterConnected: Boolean,
        @Json(name = "currencyIsoSymbol") val currencyIsoSymbol: String,
        @Json(name = "currencySymbol") val currency: String,
        @Json(name = "birthDate") val birthDate: Date?,
        @Json(name = "name") val name: String?,
        @Json(name = "profilePictureUri") val avatarUrl: String?,
        @Json(name = "gender") val gender: Gender?)

{


    val isOnboardingCompleted: Boolean
        get() = gender!= Gender.UNKNOWN && birthDate!= null && !!notificationTimePreference.isNullOrEmpty() && isPhoneNumberVerified && !email.isNullOrEmpty()
}
EN

回答 1

Stack Overflow用户

发布于 2020-10-13 06:24:05

我的方法是java。

首先,我们需要两个你可能不会在你的项目中使用的库。

gson =>,用于从字符串传递对象,反之亦然

字符串http请求的volley =>

请谷歌他们的官方github页面并安装最新版本

然后,我们将创建一个通用的结果对象来承载结果。

代码语言:javascript
复制
class Result {
   boolean error; // this field can be used by the api to tell if there was some error while processing the request
   String message; // here api can give you some extra message if there was some error
   String result; // here you get the result. you can make it a map as well if you want to receive an object and later parse to a unique object class
}

这是一个可用于HTTP请求的函数

代码语言:javascript
复制
public static Single<Result> getHttpResult(String api, Map<Stirng, String> params){
    return Single.create(emitter -> {
        StringRequest stringRequest = new StringRequest(Request.Method.POST, api, response -> {
                Log.i("RESPONSE :", response);
                try {
                    Result result = new Gson().fromJson(response, Result.java);
                    emitter.onSuccess(result);
                } catch (JSONException e) {
                    emitter.onError(e);
                }
            }, emitter::onError) {
            @Override
            protected Map<String, String> getParams() {
                return params;
            }
        };
        stringRequest.setRetryPolicy(new DefaultRetryPolicy(0, 0, 0));
        RequestQueue requestQueue = Volley.newRequestQueue(context);
        requestQueue.add(stringRequest);
    });

}

这就是你可以一次获得多个结果的方法,我建议你也检查互联网连接,如果用户有足够的互联网,那么只进行并行请求,否则就不会产生好的用户体验

代码语言:javascript
复制
...

List<Single<Result>> tasks = new ArrayList();
tasks.add(getHttpResult("https://..."), /**here you can add a map with params that your api might require for auth and other purposes**/);
tasks.add(...);
tasks.add(...);
tasks.add(...);

Single.zip(tasks, objects -> {
   List<Result> results = new ArrayList();
   for(Object object : objects){
      results.add((Result)object)
   }
   return results;
}).subscribe(results -> {
   // this result object have all the results of http requests
   // for distinguising results from each other you can create a field on the result object 
});

...

希望我的方法对您有所帮助;)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64325078

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档