通过Redrofit和Rxjava的结合使用把子线程请求的数据加载到RecyclerView并创建单例模式的Retrofit

使用单例模式创建Retrofit

单例模式是一种设计模式,它的作用是一个类只有一个示例。

在使用retrofit的单例模式时,有饿汉式单例模式和懒汉式结合synchronized的双检锁/双重校验锁模式

    1. 饿汉式优点:
      1. 线程安全
      2. 简单
    2. 双检锁/双重校验锁模式优点
      1. 节省内存,当在第一次使用时创建retrofit。
  1. 使用饿汉式
public class RetrofitClient {

    private static String URL = "https://xxx.com.cn";

    private static final Retrofit retrofit = new Retrofit.Builder()

            .baseUrl(URL)

            .addConverterFactory(GsonConverterFactory.create())//解析转换GSON代码

            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

            .build();



    public RetrofitClient() {

    }

    public static Retrofit getRetrofit() {

        return retrofit;

    }

}
  1. 使用双检锁/双重校验锁(DCL, Double Checked Locking):这种方式下,单例实例在第一次使用时创建。它结合了懒汉式和synchronized锁。
public class RetrofitClient {

    private static final String BASE_URL = "https://example.com/api/";

    private static volatile Retrofit retrofit = null;



    private RetrofitClient() {

    }  // 私有化构造函数



    public static Retrofit getInstance() {

        if (retrofit == null) {

            synchronized (RetrofitClient.class) {

                if (retrofit == null) {

                    retrofit = new Retrofit.Builder()

                        .baseUrl(BASE_URL)

                        .addConverterFactory(GsonConverterFactory.create())

                        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

                        .build();

                }

            }

        }

        return retrofit;

    }

}
    1. volatile
      1. volatile是Java中的一个关键字,用于声明一个变量为"易变的"。在Java并发编程中,它有以下的重要特性:
        1. 可见性:当一个共享变量被声明为volatile,它可以确保修改的值立即对其他线程可见。这意味着,当一个线程修改了一个volatile变量的值,其他线程读取这个变量时会看到最新的修改。
        2. 禁止指令重排:在Java中,为了提高程序的执行效率,编译器和处理器可能会对指令进行重排序。但有时这可能会导致多线程程序的不正确行为。声明变量为volatile可以确保对该变量的读/写操作不会与其它读/写操作重排序。
  1. 加载

Retrofit retrofit = RetrofitClient.getRetrofit();

GetPostRequest request = retrofit.create(GetPostRequest.class);

使用RxJava进行异步操作

retrofit的接口方法为

public interface GetPostRequest {

    @POST("/xxx/xxx")

    Flowable<TranslateListBean> requestGetListResult(@Body okhttp3.RequestBody params);

}

解释以上代码内容:

  1. @POST("xxxxxxx"):
    1. @POST:是一个Retrofit的注解,它指示这个方法会发送一个HTTP POST请求。
    2. "xxxxxxx":是请求的相对URL。假设您在Retrofit的创建时设置的基础URL为https://api.example.com/,那么完整的请求URL将是https://api.example.com/xxxxxx
  2. Flowable<TranslateListBean>
    1. Flowable:是RxJava 2中的一个类,它表示一个异步操作的结果。这表示该方法不会立即返回结果,而是返回一个表示结果的Flowable对象。
    2. TranslateListBean:是这个异步操作的结果类型。这通常是一个POJO(Plain Old Java Object),它可以通过Gson或其他JSON解析库将服务器的响应解析成Java对象。
    3. 在这里TranslateListBean是一个javaBean对象,通常是根据服务器返回的数据类型而创建的JavaBean类
  3. requestGetListResult(@Body okhttpRequestBody params):
    1. requestGetListResult:是这个方法的名称。
    2. @Body: 是一个Retrofit的注解,它指示后面的参数params应该作为请求的消息体发送。
    3. okhttp3.RequestBody:是OkHttp库中的一个类,它表示一个HTTP请求的消息体。您可以使用它来发送JSON、XML或其他类型的数据。

为什么用RxJava

  1. 在android中如果你要更新UI相关操作,那么你必须在主线程中进行,如果你的数据在IO当中,那么你有以下两种方法实现方式:
    1. 使用 Handler
Handler handler = new Handler(Looper.getMainLooper());



new Thread(new Runnable() {

    @Override

    public void run() {

        //进行网络请求或其他操作

        final String result = "你要返回的数据"

        handler.post(new Runnable() {

            @Override

            public void run() {

                translateUg = result;

                Log.d(TAG, "run: " + translateUg);

            }

        });

    }

}).start();
    1. 使用 runOnUiThread
      1. 如果你在Activity或Fragment的上下文中,你可以直接调用runOnUiThread方法:
new Thread(new Runnable() {

    @Override

    public void run() {

         //进行网络请求或其他操作

        final String result = "你要返回的数据"

        runOnUiThread(new Runnable() {

            @Override

            public void run() {

                translateUg = result;

                Log.d(TAG, "run: " + translateUg);

            }

        });

    }

}).start();
  1. 使用RxJava是因为完美解决在子线程进行网络请求之后把获取到的数据返回给主线程,更新UI。

RxJava使用

以下我使用Retrofit进行网络请求时结合RxJava实现子线程请求数据在主线程更新UI

  1. 首先引入依赖(在module:Gradle文件当中引入)
dependencies {

    //Retrofit

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'

    //Gson

    implementation "com.squareup.retrofit2:converter-gson:2.0.2"

    //RxJava设配器

    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'

    implementation 'io.reactivex.rxjava2:rxjava:2.2.21'

    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'           

}
  1. 在Retrofit时

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

  1. 使用
request.requestGetListResult(requestBody)

        .subscribeOn(Schedulers.io())//执行在io线程上

        .observeOn(AndroidSchedulers.mainThread())

        .subscribe(new Consumer<TranslateListBean>() {

            @Override

            public void accept(TranslateListBean translateListBean) throws Exception {

                //在这里更新UI

            }

        }, new Consumer<Throwable>() {

            @Override

            public void accept(Throwable throwable) throws Exception {

                //处理情况,或异常

                Log.d(TAG, "失败:" + throwable);

            }

        });
  1. 以上代码详细介绍
  1. request.requestGetListResult(requestBody):这是你Retrofit服务接口中的一个方法调用,返回一个Observable<TranslateListBean>或类似的RxJava类型。Observable是RxJava中表示一个异步操作的核心抽象。
  2. .subscribeOn(Schedulers.io()):subscribeOn指定Observable本身(即数据发射、数据流产生)在哪个调度器(Scheduler)上执行。Schedulers.io()是RxJava提供的一种调度器,它内部具有一个无界的线程池,因此可以处理大量的IO-bound工作。在这种情况下,你希望网络请求在IO线程上执行,避免在主线程上进行IO操作,因为这可能会导致UI卡顿。
  3. .observeOn(AndroidSchedulers.mainThread()):observeOn指定Observable发射的数据在哪个调度器上被消费,即你的观察者(Observer)在哪个线程上接收和处理数据。AndroidSchedulers.mainThread()是RxAndroid提供的特殊调度器,它指定观察者运行在Android主线程上。这在Android开发中是很重要的,因为UI操作(如更新视图)必须在主线程上执行。
  4. .subscribe(...):这是你开始观察Observable发射的数据的地方。当你订阅一个Observable时,你实际上启动了整个异步操作流。你提供了两个Consumer给subscribe方法:
    1. 第一个

Consumer处理成功的数据,即TranslateListBean类型的数据。当Retrofit成功完成网络请求并且数据被解析为TranslateListBean对象时,这个Consumer会被调用,并将TranslateListBean作为参数传递。

    1. 第二个

Consumer处理错误。如果在整个数据流中的任何地方出现错误,比如网络故障、数据解析错误等,这个Consumer会被调用,并将错误的Throwable作为参数传递。

总结:这段代码使用Retrofit和RxJava进行异步网络请求。请求在IO线程上执行,成功或失败的结果在Android主线程上处理。这使得你可以方便地在主线程上更新UI,而不用担心手动管理线程或处理Android的AsyncTask。

Map转换成Json并创建requestBody对象

Map<String, String> maps = new HashMap<>();

maps.put("content", content);

maps.put("source", "izdaxIME_Android");

maps.put("source_flag", "cn.izdax.ime");

//Map键值对转换成Json

String jsonParams = new Gson().toJson(maps);

//创建requestBody对象

RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);

到这里 完整代码

我是使用了饿汉式单例模式

public class RetrofitClient {

    private static String URL = "xxx/ds/ds/cn";

    private static final Retrofit retrofit = new Retrofit.Builder()

            .baseUrl(URL)

            .addConverterFactory(GsonConverterFactory.create())//解析转换GSON代码

            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

            .build();



    public RetrofitClient() {

    }

    public static Retrofit getRetrofit() {

        return retrofit;

    }

}
public interface GetPostRequest {

    @POST("/xxx/ds")

    Flowable<TranslateListBean> requestGetListResult(@Body okhttp3.RequestBody params);

}
public class NetworkRequest {

    private static final String TAG = "NetworkRequest";

    //回调方法



    public void RetrofitUgToZh(String content) {

        Map<String, String> maps = new HashMap<>();

        maps.put("content", content);

        maps.put("source", "dddd");

        maps.put("source_flag", "xxxx");

        //Map键值对转换成Json

        String jsonParams = new Gson().toJson(maps);

        //创建requestBody对象

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);

        //加载Retrofit(单例模式)

        Retrofit retrofit = RetrofitClient.getRetrofit();



        GetPostRequest request = retrofit.create(GetPostRequest.class);

        //引用RxJava

        request.requestGetListResult(requestBody)

                .subscribeOn(Schedulers.io())//执行在io线程上

                .observeOn(AndroidSchedulers.mainThread())//安卓主线程

                .subscribe(new Consumer<TranslateListBean>() {

                    @Override

                    public void accept(TranslateListBean translateListBean) throws Exception {

                           //在这里更新UI

                    }

                }, new Consumer<Throwable>() {

                    @Override

                    public void accept(Throwable throwable) throws Exception {

                       //处理情况,或异常

                            Log.d(TAG, "失败:" + throwable);

                    }

                });

    }
}

简单介绍RxJava

RxJava简介

RxJava是响应式编程的Java实现。响应式编程是一个编程范例,目的是对异步数据流进行建模。RxJava能够简化异步操作的处理,特别是在处理复杂的链式异步操作时。

RxJava的主要组件

  1. Observable (被观察者)
  2. Observer (观察者)
  3. Schedulers
  4. Operators

RxJava的用途

  1. 简化异步代码
  2. 链式操作
  3. 统一错误处理
  4. 线程切换

什么情况下使用RxJava

  1. 复杂的异步操作
  2. 处理流式数据
  3. 当你需要复用、组合或转换异步操作的结果

总结

RxJava为异步和基于事件的程序提供了一种强大而灵活的方式,允许开发者更容易地构建和理解复杂的数据流和操作链。但是,与所有工具一样,它在某些场景下可能是过度的。如果你只是进行简单的异步任务,使用其他方法,如Android的AsyncTask或Java的Future,可能会更简单。但是,当你需要处理更复杂的异步操作时,RxJava会成为一个非常有价值的工具。

使用子线程请求的数据

下面我将在RecyclerView中使用这些数据(这些返回的数据是TranslateListBean类)

浅认识安卓中的单向数据绑定

单向绑定是安卓单中非常有用的概念,它可以把JavaBean数据自动反映在UI界面,当这个数据发生变化时UI上的数据也发生实时变化,从而无需再布局页面上手动更内容。

  1. 在当前module的gradle中添加以下代码

android {

    dataBinding {

        enable=true

    }

}

  1. 修改布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    >

    <data>

        <variable

            name="ui_info"

            type="com.example.translate1.bean.InputTranslateText" />

    </data>

    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:background="@color/WhiteSmoke"

        android:clipChildren="false">

    </RelativeLayout>

</layout>

将根元素替换为layout,当我们添加<data>标签时当前页面自动设别为数据绑定布局,并自动生成和当前布局文件的名字改成驼峰命名法,以下划线后首字母大写+Binding为命名的类。例如:

布局名actytity_main.xml--->生成ActivityMainBinding的类。

  1. 绑定数据模型
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

MyViewModel viewModel = new MyViewModel();

binding.setViewModel(viewModel);
  1. InputTranslateText的内容
public class InputTranslateText {

    private String inputText;

    public String getInputText() {

        return inputText;

    }

    public void setInputText(String inputText) {

        this.inputText = inputText;

    }

}
  1. 使用
<layout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    >

    <data>

        <variable

            name="ui_info"

            type="com.example.translate1.bean.InputTranslateText" />

    </data>

    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:background="@color/WhiteSmoke"

        android:clipChildren="false">

        <TextView

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:gravity="center"

            android:text="@{ui_info.inputText}"

            android:textColor="@color/DodgerBlue" />

    </RelativeLayout>

</layout>

用@{}使用数据

在RecyclerView中使用数据绑定

  1. 在onCreateViewHolder中初始化绑定:
@Override

public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    TranslateItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.translate_item, parent, false);

    return new ViewHolder(binding);

}

  1. ViewHolder的定义:你的ViewHolder的构造函数应该接受一个绑定对象,并从绑定对象中获取itemView。
public static class ViewHolder extends RecyclerView.ViewHolder {

    final TranslateItemBinding binding;



    public ViewHolder(TranslateItemBinding binding) {

        super(binding.getRoot());

        this.binding = binding;

    }

}
  1. 在onBindViewHolder中绑定数据:
@Override

public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

    TranslateListBean item = list.get(position);

    holder.binding.setTranslate(item);

    holder.binding.executePendingBindings(); // 确保立即执行绑定

}

完整代码

public class TranslateRecyclerAdapter extends RecyclerView.Adapter<TranslateRecyclerAdapter.ViewHolder> {

    private static final String TAG = "TranslateRecyclerAdapter";

    List<TranslateListBean> list;

    Context context;



    private TranslateItemBinding binding;



    public TranslateRecyclerAdapter(List<TranslateListBean> list, Context context) {

        this.list = list;

        this.context = context;

    }



    @NonNull

    @Override

    public TranslateRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        binding = DataBindingUtil.inflate(inflater, R.layout.translate_item, parent, false);

        return new ViewHolder(binding);

    }



    @Override

    public void onBindViewHolder(@NonNull TranslateRecyclerAdapter.ViewHolder holder, int position) {

        TranslateListBean translateListBean = list.get(position);

        //执行绑定

        holder.binding.setTranslate(translateListBean);

        holder.binding.executePendingBindings();

        holder.binding.transitionInputText.setText(zh);

    }



    @Override

    public int getItemCount() {

        return list.size();

    }



    public static class ViewHolder extends RecyclerView.ViewHolder {

        final TranslateItemBinding binding;

        public ViewHolder(TranslateItemBinding binding) {

            super(binding.getRoot());

            this.binding = binding;



        }

    }

}

通过回调在activity中获得请求的数据并传给RecyclerView

public interface TranslateCallback {

    void Success(TranslateListBean translateListBean);

}

public class NetworkRequest {

    private static final String TAG = "NetworkRequest";

    public void RetrofitUgToZh(String content,TranslateCallback callback) {

        Map<String, String> maps = new HashMap<>();

        maps.put("content", content);

        maps.put("source", "xxx");

        maps.put("source_flag", "xx/cc");

        //Map键值对转换成Json

        String jsonParams = new Gson().toJson(maps);

        //创建requestBody对象

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);

        //加载Retrofit(单例模式)

        Retrofit retrofit = RetrofitClient.getRetrofit();



        GetPostRequest request = retrofit.create(GetPostRequest.class);

        //引用RxJava

        request.requestGetListResult(requestBody)

                .subscribeOn(Schedulers.io())//执行在io线程上

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(new Consumer<TranslateListBean>() {

                    @Override

                    public void accept(TranslateListBean translateListBean) throws Exception {

                        callback.Success(translateListBean);

                    }

                }, new Consumer<Throwable>() {

                    @Override

                    public void accept(Throwable throwable) throws Exception {

                        Log.d(TAG, "失败:" + throwable);

                    }

                });

    }

}

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private NetworkRequest networkRequest;

    private ActivityMainBinding binding;

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        networkRequest = new NetworkRequest();

            networkRequest.RetrofitUgToZh(text, new TranslateCallback() {

                @Override

                public void Success(TranslateListBean translateListBean) {

                    //将新添加的元素显示在最上面,translateListBean就是从服务器请求的数据。

                    list.add(0,translateListBean);

                    RecyclerView transitionRecycler = binding.transitionRecycler;

                    transitionRecycler.setAdapter(new TranslateRecyclerAdapter(list, MainActivity.this));

                    transitionRecycler.setLayoutManager(new LinearLayoutManager(MainActivity.this));

                }

            });

    }

   }

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: RxJavaRetrofit是一种经常结合使用的技术,主要是因为它们都能够协同工作,优化Android应用的性能。 具体而言,RxJava是一种响应式编程框架,可以通过异步数据流的方式处理数据Retrofit则是一个RESTful框架,用于与服务器交互。因此,RxJava可以被用于处理从Retrofit返回的数据流。 这两个框架的结合使用可以让Android应用更快地处理数据并更好地应对网络请求。同时,通过使用RxJava的转换操作符,我们可以将从Retrofit返回的数据进行快速处理和转换。 ### 回答2: RXJava是一个响应式编程库,而Retrofit则是针对REST API进行网络请求和响应解析的框架。这两者结合使用,可以实现优雅的网络请求,并让代码更加简洁易懂。 Retrofit默认使用的是同步方法,这意味着如果在主线程中执行网络请求,就会阻塞主线程,造成卡顿甚至应用崩溃。为了避免这种情况,我们可以使用RXJava中的异步调度器,将网络请求放在IO线程中执行,并在请求完成后将结果回调到主线程中处理,保证应用的流畅性和响应性。 RXJava还提供了丰富的操作符,如map、filter、flatMap等,能够对网络请求的响应数据进行快速处理和转换,将数据转换成我们需要的格式,例如对象或列表。这样在显示数据时,可以节省大量的代码和时间。 另外,由于网络请求可能出现异常、网络超时等情况,我们需要对这些异常情况进行处理。RXJava提供了专门的异常处理操作符,如onErrorReturn、onErrorResumeNext等,能够快速捕获和处理网络请求异常,并在发生异常时执行相应的操作。 综上所述,RXJavaRetrofit结合使用,能够方便地实现优雅的网络请求数据处理,以及有效地解决网络请求可能出现的异常情况,为开发者提供了更加便捷、高效、安全的开发体验。 ### 回答3: RxJavaRetrofit是目前Android开发中非常流行的两个库。他们都不是新兴的库,RxJava是由Netflix公司开发的响应式编程库,是在Java Future的基础上进行开发的。Retrofit是由Square公司开发的网络请求库。在进行Android开发时,我们一般会经常使用Retrofit来完成网络请求的操作,而配合使用RxJava可以让我们更加方便的处理网络请求的结果。 为什么要使用RxJavaRetrofitRetrofit是一个基于OkHttp的RESTful API请求框架,可以让我们通过定义相应的接口,来进行网络请求使用简单而且很快,这也是为什么它会被Android开发者广泛使用的原因。而RxJava则是将异步事件组合在一起的响应式编程库,可以让我们以响应式的方式来处理网络请求的结果。因此,当我们结合使用这两个库时,就可以更加高效地完成Android的开发。 如何使用RxJavaRetrofit使用RxJavaRetrofit大致的流程如下: 1. 在build.gradle文件中添加RetrofitRxJava的依赖: ``` implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' ``` 2. 定义Retrofit接口: ``` public interface ApiService { @GET("users") Observable<List<User>> getUsers(); } ``` 3. 使用RetrofitRxJava进行网络请求: ``` ApiService apiService = RetrofitClient.getInstance().create(ApiService.class); apiService.getUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<User>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(List<User> users) { // 成功获取到用户列表 } @Override public void onError(Throwable e) { // 网络请求失败 } @Override public void onComplete() { } }); ``` 在这个示例中,我们首先定义了一个ApiService接口,其中包含了我们需要进行网络请求的方法。在进行网络请求时,我们可以使用Retrofit的create()方法来实例化一个ApiService对象,然后使用subscribeOn()和observeOn()方法进行线程调度,最后使用subscribe()方法订阅Observer对象,即可完成网络请求的操作。 结论 RxJavaRetrofit可以很好地配合使用,使我们可以简洁、高效地处理网络请求的结果。配合使用可以大大提高我们的开发效率,同时也可以减少我们的代码量,让我们可以更加专注于业务逻辑的实现。因此,在进行Android开发时,建议使用这两个库来完成网络请求的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值