使用单例模式创建Retrofit
在使用retrofit的单例模式时,有饿汉式单例模式和懒汉式结合synchronized的双检锁/双重校验锁模式
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;
}
}
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;
}
}
Retrofit retrofit = RetrofitClient.getRetrofit();
GetPostRequest request = retrofit.create(GetPostRequest.class);
使用RxJava进行异步操作
public interface GetPostRequest {
@POST("/xxx/xxx")
Flowable<TranslateListBean> requestGetListResult(@Body okhttp3.RequestBody params);
- @POST("xxxxxxx"):
- @POST:是一个Retrofit的注解,它指示这个方法会发送一个HTTP POST请求。
- "xxxxxxx":是请求的相对URL。假设您在Retrofit的创建时设置的基础URL为https://api.example.com/,那么完整的请求URL将是https://api.example.com/xxxxxx。
- Flowable<TranslateListBean>:
- requestGetListResult(@Body okhttpRequestBody params):
为什么用RxJava
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();
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();
RxJava使用
以下我使用Retrofit进行网络请求时结合RxJava实现子线程请求数据在主线程更新UI
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'
}
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
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);
}
});
- request.requestGetListResult(requestBody):这是你Retrofit服务接口中的一个方法调用,返回一个Observable<TranslateListBean>或类似的RxJava类型。Observable是RxJava中表示一个异步操作的核心抽象。
- .subscribeOn(Schedulers.io()):subscribeOn指定Observable本身(即数据发射、数据流产生)在哪个调度器(Scheduler)上执行。Schedulers.io()是RxJava提供的一种调度器,它内部具有一个无界的线程池,因此可以处理大量的IO-bound工作。在这种情况下,你希望网络请求在IO线程上执行,避免在主线程上进行IO操作,因为这可能会导致UI卡顿。
- .observeOn(AndroidSchedulers.mainThread()):observeOn指定Observable发射的数据在哪个调度器上被消费,即你的观察者(Observer)在哪个线程上接收和处理数据。AndroidSchedulers.mainThread()是RxAndroid提供的特殊调度器,它指定观察者运行在Android主线程上。这在Android开发中是很重要的,因为UI操作(如更新视图)必须在主线程上执行。
- .subscribe(...):这是你开始观察Observable发射的数据的地方。当你订阅一个Observable时,你实际上启动了整个异步操作流。你提供了两个Consumer给subscribe方法:
Consumer处理成功的数据,即TranslateListBean类型的数据。当Retrofit成功完成网络请求并且数据被解析为TranslateListBean对象时,这个Consumer会被调用,并将TranslateListBean作为参数传递。
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是响应式编程的Java实现。响应式编程是一个编程范例,目的是对异步数据流进行建模。RxJava能够简化异步操作的处理,特别是在处理复杂的链式异步操作时。
RxJava为异步和基于事件的程序提供了一种强大而灵活的方式,允许开发者更容易地构建和理解复杂的数据流和操作链。但是,与所有工具一样,它在某些场景下可能是过度的。如果你只是进行简单的异步任务,使用其他方法,如Android的AsyncTask或Java的Future,可能会更简单。但是,当你需要处理更复杂的异步操作时,RxJava会成为一个非常有价值的工具。
使用子线程请求的数据
下面我将在RecyclerView中使用这些数据(这些返回的数据是TranslateListBean类)
浅认识安卓中的单向数据绑定
单向绑定是安卓单中非常有用的概念,它可以把JavaBean数据自动反映在UI界面,当这个数据发生变化时UI上的数据也发生实时变化,从而无需再布局页面上手动更内容。
android {
dataBinding {
enable=true
}
<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的类。
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MyViewModel viewModel = new MyViewModel();
binding.setViewModel(viewModel);
public class InputTranslateText {
private String inputText;
public String getInputText() {
return inputText;
}
public void setInputText(String inputText) {
this.inputText = inputText;
}
}
<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中使用数据绑定
@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);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
final TranslateItemBinding binding;
public ViewHolder(TranslateItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
@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));
}
});
}
}