使用 Kotlin 进行 RxJava 和改造

Posted

技术标签:

【中文标题】使用 Kotlin 进行 RxJava 和改造【英文标题】:RxJava and Retrofit using Kotlin 【发布时间】:2018-05-03 17:00:26 【问题描述】:

如何在 Kotlin 中使用 RxJava 和 Retrofit 创建用于 api 调用的泛型类?

我的 JAVA 实现是 ::

首先添加 Gradle 依赖项:(如果可用,更新到最新版本)

//用于改造

实现'com.squareup.retrofit2:retrofit:2.3.0'

实现'com.squareup.retrofit2:converter-gson:2.3.0'

//用于拦截器 实现 'com.squareup.okhttp3:logging-interceptor:3.9.0'

//对于 BuildType : (如果你想要各种环境)

构建类型 调试 buildConfigField "String", "SERVER_URL", '"DEV_URL"' 可调试真 发布 buildConfigField "String", "SERVER_URL", '"LIVE_URL"' 缩小启用假

//如果设置了环境使用设置环境定义BASE_URL:

字符串 BASE_URL = BuildConfig.SERVER_URL + "url";

================================================ ======== 为 Retrofit Builder 创建一个名为 RestClient 的类:

public class RestClient 

private static RestClient instance;
private ApiConstant apiInterface;
private OkHttpClient.Builder okHttpClientBuilder;

public RestClient() 
    instance = this;
    okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder.connectTimeout(60, TimeUnit.SECONDS);
    okHttpClientBuilder.writeTimeout(60, TimeUnit.SECONDS);
    okHttpClientBuilder.readTimeout(60, TimeUnit.SECONDS);


//for logs of api response in debug mode

    if (BuildConfig.DEBUG) 
        final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        okHttpClientBuilder.addInterceptor(interceptor);
    


public static RestClient getInstance() 
    return instance;


public ApiConstant getApiInterface() 

    final Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
    retrofitBuilder.baseUrl(ApiConstant.BASE_URL);
    retrofitBuilder.client(okHttpClientBuilder.build());
    retrofitBuilder.addConverterFactory(GsonConverterFactory.create());

    Retrofit retrofit = retrofitBuilder.build();
    apiInterface = retrofit.create(ApiConstant.class);

    return apiInterface;

================================================ ======== ApiInterface : (api调用的接口)

public interface ApiInterface 

@POST("Urls Params")
Call<ModelClass> postValidateToken(@Body JSONObject body);


================================================ ======== 创建名为 RetrofitCallback 的通用类,它处理 Api 响应并引发基本错误并向用户显示 Toast 消息:

public abstract class RetrofitCallback<T> implements Callback<T> 

private ProgressDialog progressDialog;
private Context context;
private boolean validateResponse = true;

public RetrofitCallback(Context c) 
    context = c;


public RetrofitCallback(Context c, ProgressDialog dialog) 
    progressDialog = dialog;
    context = c;


    public RetrofitCallback(Context context, ProgressDialog progressDialog, boolean validateResponse) 
    this.progressDialog = progressDialog;
    this.context = context;
    this.validateResponse = validateResponse;


public RetrofitCallback(Context context, boolean validateResponse) 
    this.context = context;
    this.validateResponse = validateResponse;


public abstract void onSuccess(T arg0);

@Override
public void onResponse(Call<T> call, Response<T> response) 

    if (!(((Activity) context).isFinishing()) && progressDialog != null && progressDialog.isShowing()) 
        if (progressDialog != null && progressDialog.isShowing()) 
            progressDialog.dismiss();
        
    

    if (response.isSuccessful() && response.code() == 200) 
        onSuccess(response.body());
     else 
        Toast.makeText(context, context.getString(R.string.something_wrong), Toast.LENGTH_SHORT).show();
    


@Override
public void onFailure(Call<T> call, Throwable error) 
    if (!validateResponse)
        return;

    String errorMsg;
    error.printStackTrace();
    if (error instanceof SocketTimeoutException) 
        errorMsg = context.getString(R.string.connection_timeout);
     else if (error instanceof UnknownHostException) 
        errorMsg = context.getString(R.string.nointernet);
     else if (error instanceof ConnectException) 
        errorMsg = context.getString(R.string.server_not_responding);
     else if (error instanceof JSONException || error instanceof JsonSyntaxException) 
        errorMsg = context.getString(R.string.parse_error);
     else if (error instanceof IOException) 
        errorMsg = error.getMessage();
     else 
        errorMsg = context.getString(R.string.something_wrong);
    

    if (progressDialog != null && progressDialog.isShowing()) 
        if (progressDialog != null && progressDialog.isShowing()) 
            progressDialog.dismiss();
        
    
    Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show();


================================================ ======== 字符串:(字符串.xml)

出了点问题。请稍后再试。 没有可用的互联网连接。请稍后再试。 服务器没有响应。请稍后再试。 连接超时 无法解析来自服务器的响应

================================================ ======== 实现(如何在Activity或Fragment中调用):

 Call<User> userLoginCall = RestClient.getInstance().getApiInterface().LoginURL(Util.currentLanguage,
                Util.getLoginURL(getActivity(), email, LOGIN_GOOGLE, accID));
        userLoginCall.enqueue(new RetrofitCallback<User>(getActivity(), DialogUtils.showProgressDialog(getActivity())) 
            @Override
            public void onSuccess(User user) 

                //Your Response
            
        );

【问题讨论】:

“泛型类”是什么意思,到目前为止您尝试过什么? 我是 kotlin 的新手,所以我想通过创建一个直接处理错误并直接给出 onSuccess 的通用类来简化我的 api 调用使用 RxJava... github.com/ApploverSoftware/android_architecture/tree/master/… github.com/ApploverSoftware/android_architecture/blob/master/… 我现在没有时间解释它(如果你需要的话,可能稍后再解释)。我的架构旨在使用 zip 或 merge 等 rx 方法更轻松地优化代码。 您可以使用这个适配器库,以便您可以将 RxJava 与 Retrofit 一起使用:github.com/square/retrofit/tree/master/retrofit-adapters/…retrofitBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) 【参考方案1】:

我使用一个 ServiceGenerator 类,以防我需要使用多个 Retrofit Service 接口。

object ServiceGenerator 

    const val APP_CODE = "APP_CODE"

    private val interceptor = HttpLoggingInterceptor()
        .setLevel(HttpLoggingInterceptor.Level.BODY)

    private val certificatePinner = CertificatePinner.Builder()
        .add(BuildConfig.HOSTNAME, BuildConfig.SHA1_HASH1)
        .add(BuildConfig.HOSTNAME, BuildConfig.SHA1_HASH2)
        .add(BuildConfig.HOSTNAME, BuildConfig.SHA1_HASH3)
        .add(BuildConfig.HOSTNAME, BuildConfig.SHA1_HASH4)
        .build()

    private val httpClient = OkHttpClient.Builder()
        .readTimeout(1, TimeUnit.MINUTES)
        .connectTimeout(1, TimeUnit.MINUTES)
        .addInterceptor(interceptor)

    private val builder = Retrofit.Builder()
        .baseUrl(BuildConfig.URL_ENDPOINT)
        .addCallAdapterFactory(
                    RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())
        )
        .addConverterFactory(GsonConverterFactory.create())

    private var requestInterceptor: AppEventosRequestInterceptor? = null

    fun <S> createService(context: Context, serviceClass: Class<S>): S 
        if (BuildConfig.FLAVOR.equals("production")) 
            httpClient.certificatePinner(certificatePinner)
        
        if (!httpClient.interceptors().contains(requestInterceptor)) 
            requestInterceptor = AppEventosRequestInterceptor(context)
            httpClient.addInterceptor(requestInterceptor!!)
        
        builder.client(httpClient.build())
        val retrofit = builder.build()
        return retrofit.create(serviceClass)
    

在我的例子中,我让我的服务能够返回一个 Flowable 响应,以便我可以观察它。

@GET("schedule")
fun getSchedules(
        @Header("If-None-Match") etag: String
): Flowable<Response<ResponseBody>>

然后,当我想进行 http 调用时,我首先初始化我的 ServiceRx 类

private var mService: AppEventosServiceRx = ServiceGenerator.createService<AppEventosServiceRx>(applicationContext, AppEventosServiceRx::class.java)

然后提出我的要求

mService.getSchedules(mEtagManager.getEtag(EtagManager.ETAG_SCHEDULES))
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
         response ->
            if (response.code() != HttpURLConnection.HTTP_NOT_MODIFIED) 
                if (response.body() != null) 
                    // Do your useful stuff here...
                
             else 
                // Check if not modified or any other HTTP Error
            
        ,
         throwable -> 
            // Log your connectivity problems ...
        
    ) 

这样,您的服务接口将为您提供一个观察者,服务生成器将使其对每个调用都通用,您可以观察它并处理响应。

希望对你有帮助!

【讨论】:

以上是关于使用 Kotlin 进行 RxJava 和改造的主要内容,如果未能解决你的问题,请参考以下文章

使用改造对 mvvm 中的 Rxjava 进行错误处理

Rxjava,改造和多次调用

使用 Kotlin 处理错误 RXJava Android

使用 rxJava 和改造多次调用另一个请求中的请求

Rxjava 2 - 使用领域和改造获取数据

RxJava 和改造的单元测试