大家好,我又来了,今天抽点时间来把上次没分享完的分享完一下,也是在把基础框架运用到实际项目的第一周,顺便把我上次想分享而又来不及的另一种基础封装中的获取数据方式分享一下
没上看一篇的同学可以先去了解了解哈
一、话不多说,先上更改的获取服务器数据的代码
修改获取服务器数据方式后的代码片段 BaseGetDataActivity
public abstract class BaseGetDataActivity<T> extends BaseHeaderActivity {
public T t;
@Override
public void initData() {
intoHttp();
}
public void intoHttp() {
HttpClient.getInstance().doWithToken(this, getObservable(), new CallbackObserver<T>(this) {
@Override
public void onSuccess(BaseResponse<T> httpResult) {
t = httpResult.result;
initRefreshView();
}
});
}
public abstract void initRefreshView();
public abstract Observable<BaseResponse<T>> getObservable();
}
doWithToken方法,我是放在一个统一管理类中的
public <T> void doWithToken(Context context, Observable<BaseResponse<T>> observable, CallbackObserver<T> callback) {
observable.compose(SchedulerProvider.getInstance().observableIO2Main(context)).subscribe(callback);
}
区别我想大家应该都看明白了,就是在于把Observable<BaseResponse>放到实现类去实现,避免了泛型擦除的问题,从而使得直接可以拿到数据结果,并且可以在BaseGetDataActivity中把所有错误情况预先默认处理一遍,特殊的在重写父类方法进行处理,也不需要实现url方法和map方法了,可以直接在ApiService类中写明接口访问方式和参数。
接口实现方式前后对比
@GET
Observable<ResponseBody> executeGet(@Url String url,@QueryMap Map<String, String> mapsP);
@GET("v1/xxxxx/xxxxxx")
Observable<BaseBean> updateItemStatu(@Query("itemId") String itemId);
个人比较喜欢后者,也更优一些,但是前者的也不失为节省代码量,减少bug的好方法哦,至于
Headers大家可以在okhttp中addInterceptor拦截添加,处理。
访问网络错误的处理逻辑我统一封装在了CallbackObserver中,继承DisposableObserver<BaseResponse>实现,由于不同的业务有着不同的处理,这里就不贴出来了,大致就是onStart中是否弹出加载框,onComplete中非空隐藏加载框,onError中对常见错误的Toast,onNext中根据服务器返回的数据基础模型code做出相应的处理,例如Token失效重新登陆等等的统一处理。
当然如果项目需要,比如处理一些网络异常的通用界面展示,无网络界面展示等等,那也可以重写CallbackObserver中的onError方法在BaseGetDataActivity中统一处理操作,这样做的好处就是节省代码量,节省时间,避免每次碰到这种界面都需要捋一遍逻辑代码在写,一次成功,永无bug
根据BaseGetDataActivity同理可得单纯的提交数据类的写法
二、单纯的提交数据类的写法 BaseUpDataActivity
public abstract class BaseUpDataActivity<T> extends BaseHeaderActivity {
public T t;
public void intoHttp() {
HttpClient.getInstance().doWithToken(this, getObservable(), new CallbackObserver<T>(this) {
@Override
public void onSuccess(BaseResponse<T> httpResult) {
t = httpResult.result;
initRefreshView();
}
});
}
/**
* 默认提交数据完成的操作
*/
public void initRefreshView() {
toFinish();
}
public abstract Observable<BaseResponse<T>> getObservable();
}
在上面已经解释了BaseGetDataActivity的操作了,那这里就没什么解释的必要了,直接来上篇省略了的既要拉取数据,又要提交数据的Base封装吧,国际惯例,先上代码
三、既要拉取数据,又要提交数据的Base封 BaseDataActivity
BaseDataActivity
public abstract class BaseDataActivity<T, A> extends BaseHeaderActivity {
public T t;//拉取数据的bean
public A a;//提交数据服务器返回的bean,一半都返回BaseResponse就够了,
@Override
public void initData() {
doGetData(this);
}
public void doGetData() {
HttpClient.getInstance().doWithToken(this, getObservable(), new CallbackObserver<T>() {
@Override
public void onSuccess(BaseResponse<T> httpResult) {
t = httpResult.result;
initRefreshView();
}
});
}
public void doGetData(Context context) {
HttpClient.getInstance().doWithToken(this, getObservable(), new CallbackObserver<T>(context) {
@Override
public void onSuccess(BaseResponse<T> httpResult) {
t = httpResult.result;
initRefreshView();
}
});
}
public void doUpData() {
HttpClient.getInstance().doWithToken(this, upObservable(), new CallbackObserver<A>() {
@Override
public void onSuccess(BaseResponse<A> httpResult) {
a = httpResult.result;
if (a != null)
initUpDataRefresh();
}
});
}
public void doUpData(Context context) {
HttpClient.getInstance().doWithToken(this, upObservable(), new CallbackObserver<A>(context) {
@Override
public void onSuccess(BaseResponse<A> httpResult) {
a = httpResult.result;
if (a != null)
initUpDataRefresh();
}
});
}
public void doUpDataGetData() {
upObservable().compose(SchedulerProvider.getInstance().observableIO2IO(this)).flatMap((Function<BaseResponse<A>, ObservableSource<BaseResponse<T>>>) base -> {
if (base != null) {
if (base.getCode() == Constant.ACCESS_SUCCESSFUL) {
return getObservable();
}
BaseResponse<T> baseResponse=new BaseResponse<>();
baseResponse.code=base.code;
baseResponse.message=base.message;
baseResponse.result=null;
return Observable.just(baseResponse) ;
}
return null;
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new CallbackObserver<T>(){
@Override
public void onSuccess(BaseResponse<T> httpResult) {
hideLoading();
if(httpResult==null)return ;
t = httpResult.result;
if (t != null)
initRefreshView();
}
});
}
public abstract void initRefreshView();
public abstract void initUpDataRefresh();
public abstract Observable<BaseResponse<T>> getObservable();
public abstract Observable<BaseResponse<A>> upObservable();
}
一个个来分析,doGetData,doUpData两个方法为什么要重载呢,一开始我也没有写重载的,而是每次访问都会加载loading,一半情况呢,也是够用的,但是有些业务,需要在你提交数据之后再次刷新界面改变状态,读取一些数据的时候,那么loading就冲突了,于是就有了重载,控制loading的显示与不显示,带context就代表需要loading,
但是我又一想,既然提交之后又要拉取,那我何不利用rxjava的操作符合并一下接口,flatMap,在提交接口访问完成并且成功的时候调用刷新接口,两者合并,也就是方法doUpDataGetData,实现类这边就不展示了,因为没有写test类,直接写的实际业务功能,不便展示,接下来就是列表界面代码修改片段了
三、列表类的访问服务器修改
修改了访问服务器的,还修改了空界面,错误界面,无网络界面处理,添加了getHeaderUiView,addFooterUiView,非列表中的头和尾,更具有包容性
BaseDataActivity
public abstract class BaseItemActivity<T> extends BaseHeaderActivity implements AdapterCoverHelper<T> {
@BindView(R.id.mRecyclerView)
public RecyclerView mRecyclerView;
@BindView(R.id.mNestedScrollView)
public NestedScrollView mNestedScrollView;
@BindView(R.id.refreshLayout)
public SmartRefreshLayout refreshLayout;
@BindView(R.id.img_empty)
ImageView imgEmpty;
@BindView(R.id.view_empty_msg)
TextView viewEmptyMsg;
@BindView(R.id.view_empty_layout)
LinearLayout viewEmptyLayout;
@BindView(R.id.view_error_msg)
TextView viewErrorMsg;
@BindView(R.id.view_error_layout)
LinearLayout viewErrorLayout;
@BindView(R.id.view_no_connected_layout)
FrameLayout viewNoConnectedLayout;
@BindView(R.id.layout_header_view)
public FrameLayout layoutHeaderView;
@BindView(R.id.layout_footer_view)
public FrameLayout layoutFooterView;
public List<T> items = new ArrayList<>();
public BaseItemAdapter<T> baseItemAdapter;
public int pageNo = 1, pageSize = 20;
public boolean isLoadMore = true;
@Override
public int getContentLayoutId() {
return R.layout.activity_baseitem;
}
@Override
protected void initView() {
super.initView();
initRecyclerView();
initAdapterView();
}
public void initRecyclerView() {
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
initDividerItemDecoration();
mRecyclerView.setFocusable(false);
}
public void initAdapterView() {
baseItemAdapter = new BaseItemAdapter(mRecyclerView, getItemLayoutId(), this);
baseItemAdapter.setData(items);
//baseItemAdapter.notifyDataSetChanged();
if (getHeaderView() != null) baseItemAdapter.addHeaderView(getHeaderView());
if (addFooterView() != null) baseItemAdapter.addFooterView(addFooterView());
if (getHeaderView() == null && addFooterView() == null)
mRecyclerView.setAdapter(baseItemAdapter);
else
mRecyclerView.setAdapter(baseItemAdapter.getHeaderAndFooterAdapter());
if (getHeaderUiView() != null) layoutHeaderView.addView(getHeaderUiView());
if (addFooterUiView() != null) layoutFooterView.addView(addFooterUiView());
}
@Override
public void initListener() {
refreshLayout.setRefreshHeader(new ClassicsHeader(this));
refreshLayout.setRefreshFooter(new ClassicsFooter(this));
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
if (isLoadMore)
isOpenLoadMore(true);
pageNo = 1;
items.clear();
initHttpData();
}
});
refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(RefreshLayout refreshlayout) {
initHttpData();
}
});
refreshLayout.autoRefresh();
}
public void initHttpData() {
if (isIntoHttp())
doGetWithToken();
}
public abstract int getItemLayoutId();
public abstract Observable<BaseResponse<List<T>>> getObservable();
public boolean isDividerItemDecoration() {
return true;
}
public void initDividerItemDecoration() {
if (isDividerItemDecoration()) {
DividerItemDecoration divider = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
divider.setDrawable(ContextCompat.getDrawable(this, R.drawable.recommend_item_divider));
mRecyclerView.addItemDecoration(divider);
}else {
mRecyclerView.addItemDecoration(new DividerItemVerticalDefault());
}
}
/**
* 是否进来就加载
*
* @return
*/
public boolean isIntoHttp() {
return true;
}
public View getHeaderView() {
return null;
}
public View addFooterView() {
return null;
}
public View getHeaderUiView() {
return null;
}
public View addFooterUiView() {
return null;
}
public void initSuccess(BaseResponse<List<T>> response) {
if (isSize(response.result)) {
initSetState(Constant.STATE_SUCCESS);
items.addAll(response.result);
baseItemAdapter.setData(items);
} else {
initSetState(Constant.STATE_EMPTY);
isOpenLoadMore(false);
}
}
public void initSuccess(List<T> response) {
if (isSize(response)) {
initSetState(Constant.STATE_SUCCESS);
items.addAll(response);
baseItemAdapter.setData(items);
} else {
initSetState(Constant.STATE_EMPTY);
isOpenLoadMore(false);
}
}
public void initError(Throwable response) {
ToastUtil.showToastError(response.getMessage());
initErrorFinishRefreshAndLoadMore();
}
public void initSetState(int state) {
switch (state) {
case Constant.STATE_SUCCESS:
initSuccessFinishRefreshAndLoadMore();
viewEmptyLayout.setVisibility(View.GONE);
viewErrorLayout.setVisibility(View.GONE);
viewNoConnectedLayout.setVisibility(View.GONE);
break;
case Constant.STATE_EMPTY:
initErrorFinishRefreshAndLoadMore();
if (baseItemAdapter.getData().size() == 0) {
viewEmptyLayout.setVisibility(View.VISIBLE);
viewErrorLayout.setVisibility(View.GONE);
viewNoConnectedLayout.setVisibility(View.GONE);
}
break;
case Constant.STATE_ERROR:
initErrorFinishRefreshAndLoadMore();
if (baseItemAdapter.getData().size() == 0) {
viewEmptyLayout.setVisibility(View.GONE);
viewErrorLayout.setVisibility(View.VISIBLE);
viewNoConnectedLayout.setVisibility(View.GONE);
}
break;
case Constant.STATE_CONNECTED:
initErrorFinishRefreshAndLoadMore();
if (baseItemAdapter.getData().size() == 0) {
viewEmptyLayout.setVisibility(View.GONE);
viewErrorLayout.setVisibility(View.GONE);
viewNoConnectedLayout.setVisibility(View.VISIBLE);
}
break;
}
}
/**
* 成功拉取服务器数据,刷新拉取时间
*
* @param isRefresh true 下拉刷新结束 false 上拉加载结束
*/
private void initSuccessFinishRefreshAndLoadMore(boolean isRefresh) {
if (refreshLayout == null) return;
if (isRefresh) {
refreshLayout.finishRefresh(true);
} else {
refreshLayout.finishLoadMore(true);
}
}
/**
* 访问服务器失败,不刷新拉取时间
*
* @param isRefresh true 下拉刷新结束 false 上拉加载结束
*/
private void initErrorFinishRefreshAndLoadMore(boolean isRefresh) {
if (refreshLayout == null) return;
if (isRefresh) {
refreshLayout.finishRefresh(false);
} else {
refreshLayout.finishLoadMore(false);
}
}
/**
* 是否开启上拉加载,未满一屏则默认不可下拉加载
*
* @param isOpen
*/
public void isOpenLoadMore(boolean isOpen) {
isLoadMore = isOpen;
if (refreshLayout == null) return;
refreshLayout.setEnableLoadMore(isOpen);
}
private void initErrorFinishRefreshAndLoadMore() {
if (refreshLayout == null) return;
switch (refreshLayout.getState()) {
case Refreshing:
refreshLayout.finishRefresh(false);
break;
case Loading:
refreshLayout.finishLoadMore(false);
break;
case None:
break;
default:
refreshLayout.setNoMoreData(false);
}
}
private void initSuccessFinishRefreshAndLoadMore() {
if (refreshLayout == null) return;
switch (refreshLayout.getState()) {
case Refreshing:
refreshLayout.finishRefresh(true);
break;
case Loading:
refreshLayout.finishLoadMore(true);
break;
case None:
break;
default:
refreshLayout.setNoMoreData(true);
}
}
public void doGetWithToken() {
getObservable().compose(SchedulerProvider.getInstance().observableIO2Main(this)).subscribe(new CallbackObserver<List<T>>() {
@Override
public void onSuccess(BaseResponse<List<T>> httpResult) {
initSuccess(httpResult);
}
@Override
public void onError(Throwable e) {
super.onError(e);
if (e instanceof SocketTimeoutException || e instanceof ConnectException || e instanceof UnknownHostException) {
initSetState(Constant.STATE_CONNECTED);
}
}
@Override
protected void onFailed(BaseResponse<List<T>> tHttpResult) {
super.onFailed(tHttpResult);
initSetState(Constant.STATE_ERROR);
}
});
}
}
xml类
<com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zhy="http://schemas.android.com/apk/res-auto"
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/layout_header_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v4.widget.NestedScrollView
android:id="@+id/mNestedScrollView"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false" />
</android.support.v4.widget.NestedScrollView>
<include layout="@layout/view_empty_layout" />
<include layout="@layout/view_error_layout" />
<include layout="@layout/view_no_connected_layout" />
<FrameLayout
android:id="@+id/layout_footer_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
可以看到,除了更换了网络访问方式,还修改了空界面,错误界面,无网络界面的处理方式,不在是用自定义控件实现,这种更加便于修改和理解。
再者就是加了getHeaderUiView,addFooterUiView,两个方法,使得可以兼容更多的界面情况,这里就不用多分析了,改分析的都在上面分析完了,各种界面的显示判断相信大家应该都知道
下面介绍下多列表封装的使用
多列表base封装
多列表,也就是复杂的,多种类型的列表界面,可以选择单个单个fragment写,当然也可以使用多列表了,唉,算了,看了下以前封装的多列表基类,发现还是用的不是最新的rxjava2+retrofit2+okhttp3+rxlifecycle2之类,那就等我五一的时候换一下并且测试一下在给大家分享吧,省的误人子弟啊哈哈,抱歉抱歉,五一一定补上。
这次就介绍到这里了,更新多列表的分享我会直接在接在本篇文章之后
本篇文章旨在于让大家如何高效快速的编写代码,并且减少因为漏写,疏忽而导致的bug
偷懒一时爽,一直偷懒一直爽,哈哈。大神请轻喷,也欢迎指点小弟一二