依赖配置
// 网络请求依赖
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.6.1'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
kotlin版本
ext.kotlin_version = '1.6.10'
实现思路
为了使Activity、Fragment中的代码简洁,并减少业务或数据访问造成的代码侵入,最开始想通过MVP三层架构的形式进行分层,碍于小公司人少,MVP实现起来过于啰嗦。想到retrofit可以通过添加工件的方式使用Rxjava进行管理,但还是显得有些不够优雅。
改造前代码
package com.wandao.myapplication.fragments.settings
import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.wandao.myapplication.R
import com.wandao.myapplication.http.ServiceCreator
import com.wandao.myapplication.http.httpBean.CabinetList
import com.wandao.myapplication.http.httpService.CabinetService
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
class BindCabinetFragment : Fragment() {
val TAG = "BindCabinetFragment"
var disposable : Disposable? = null
var activity : AppCompatActivity? = null
override fun onAttach(context: Context) {
super.onAttach(context)
activity = context as AppCompatActivity
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_bind_cabinet, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
private fun initView() {
val observable = ServiceCreator.create<CabinetService>().getCabinetList()
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<CabinetList> {
override fun onSubscribe(d: Disposable) {
Log.d(TAG, "onSubscribe: ")
disposable = d
}
override fun onNext(t: CabinetList) {
Log.d(TAG, "onNext: getCabinetList返回:"+t.toString())
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
Log.d(TAG, "onComplete: ")
}
})
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy: ")
disposable?.let {
if (!it.isDisposed) it.dispose()
}
}
}
改造后
package com.wandao.myapplication.fragments.settings
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.wandao.myapplication.R
import com.wandao.myapplication.bean.MyEvents
import com.wandao.myapplication.config.RxBusCode
import com.wandao.myapplication.expand.getCabinetList
import com.wandao.myapplication.http.httpBean.CabinetList
import com.wandao.myapplication.utils.RxBus
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
class BindCabinetFragment : Fragment() {
val TAG = "BindCabinetFragment"
var disposable : Disposable? = null
var activity : AppCompatActivity? = null
override fun onAttach(context: Context) {
super.onAttach(context)
activity = context as AppCompatActivity
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_bind_cabinet, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
@SuppressLint("CheckResult")
private fun initView() {
//准备接收事件
RxBus.getInstance().toObservable(this,MyEvents::class.java).observeOn(AndroidSchedulers.mainThread()).subscribe {
when(it.code){
RxBusCode.HTTPDATAS ->{
val data = it.data as CabinetList
Log.d(TAG, "httpData's: $data")
}
RxBusCode.HTTPERROR ->{
val data = it.data as Throwable
Log.d(TAG, "httpError: ${data.printStackTrace()}")
}
RxBusCode.HTTPDISPOSABLE ->{
disposable = it.data as Disposable
}
}
}
//发送请求事件
activity?.getCabinetList()
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy: ")
disposable?.let {
if (!it.isDisposed) it.dispose()
}
}
}
最终通过kotlin的扩展函数,使在Activity和Fragment中不再需要关注网络请求的实现,并通过对Rxjava的二次封装,使网络请求从以前的调用变成发送,抽离重复代码,提高开发效率。
kotlin扩展函数
fun AppCompatActivity.getCabinetList(){
RxjavaSendFactory.getInstance.sendObservable(ObserverFactory.getInstance.getCabinetList())
}
ObserverFactory
package com.wandao.myapplication.http
import com.wandao.myapplication.http.httpBean.CabinetList
import com.wandao.myapplication.http.httpService.CabinetService
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.annotations.NonNull
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
class ObserverFactory private constructor(){
companion object{
val getInstance : ObserverFactory by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
ObserverFactory()
}
}
fun getCabinetList(): @NonNull Observable<CabinetList> {
return observableThread(ServiceCreator.create<CabinetService>().getCabinetList())
}
fun <T>observableThread(observable: Observable<T>) : Observable<T>{
return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
}
}
RxjavaSendFactory
package com.wandao.myapplication.http
import com.wandao.myapplication.bean.MyEvents
import com.wandao.myapplication.config.RxBusCode
import com.wandao.myapplication.utils.RxBus
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
class RxjavaSendFactory private constructor(){
companion object{
val getInstance : RxjavaSendFactory by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
RxjavaSendFactory()
}
}
fun <T> sendObservable(observable: Observable<T>){
observable.subscribe(object : Observer<T>{
override fun onSubscribe(d: Disposable) {
RxBus.getInstance().post(MyEvents(RxBusCode.HTTPDISPOSABLE,"",d))
}
override fun onNext(t: T) {
RxBus.getInstance().post(MyEvents(RxBusCode.HTTPDATAS,"",t))
}
override fun onError(e: Throwable) {
RxBus.getInstance().post(MyEvents(RxBusCode.HTTPERROR,"",e))
}
override fun onComplete() {}
})
}
}
RxBus(基于Rxjava2.0版本实现)
//RxJava
implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
// 使用Android生命周期作为提供者
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'
package com.wandao.myapplication.utils;
import android.annotation.SuppressLint;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle;
import com.trello.rxlifecycle2.LifecycleProvider;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
public class RxBus {
private volatile static RxBus mDefaultInstance;
private final Subject<Object> mBus;
private final Map<Class<?>, Object> mStickyEventMap;
private RxBus() {
mBus = PublishSubject.create().toSerialized();
mStickyEventMap = new ConcurrentHashMap<>();
}
public static RxBus getInstance() {
if (mDefaultInstance == null) {
synchronized (RxBus.class) {
if (mDefaultInstance == null) {
mDefaultInstance = new RxBus();
}
}
}
return mDefaultInstance;
}
/**
* 发送事件
*/
@SuppressLint("CheckResult")
public void post(Object event) {
mBus.onNext(event);
}
/**
* 使用Rxlifecycle解决RxJava引起的内存泄漏
*/
public <T> Observable<T> toObservable(LifecycleOwner owner, final Class<T> eventType) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
return mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
}
/**
* 判断是否有订阅者
*/
public boolean hasObservers() {
return mBus.hasObservers();
}
public void reset() {
mDefaultInstance = null;
}
/**
* Stciky 相关
*/
/**
* 发送一个新Sticky事件
*/
public void postSticky(Object event) {
synchronized (mStickyEventMap) {
mStickyEventMap.put(event.getClass(), event);
}
post(event);
}
/**
* 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
* 使用Rxlifecycle解决RxJava引起的内存泄漏
*/
public <T> Observable<T> toObservableSticky(LifecycleOwner owner,final Class<T> eventType) {
synchronized (mStickyEventMap) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
Observable<T> observable = mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
final Object event = mStickyEventMap.get(eventType);
if (event != null) {
return observable.mergeWith(Observable.create(new ObservableOnSubscribe<T>() {
@Override
public void subscribe(ObservableEmitter<T> subscriber) throws Exception {
subscriber.onNext(eventType.cast(event));
}
}));
} else {
return observable;
}
}
}
/**
* 根据eventType获取Sticky事件
*/
public <T> T getStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.get(eventType));
}
}
/**
* 移除指定eventType的Sticky事件
*/
public <T> T removeStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.remove(eventType));
}
}
/**
* 移除所有的Sticky事件
*/
public void removeAllStickyEvents() {
synchronized (mStickyEventMap) {
mStickyEventMap.clear();
}
}
}
MyEvents
package com.wandao.myapplication.bean
data class MyEvents<T>(
var code : String,
var message : String,
var data : T
)
最终在Activity或Fragment中的调用方式,见改造后