优雅地处理加载中(loading),重试(retry)和⽆数据
(empty)等---LoadSir
LoadSir是⼀个⾼效易⽤,低碳环保,扩展性良好的加载反馈页管理框架,在加载⽹络或其他数据时候,根据需求切换状态页⾯,可添加⾃定义状态页⾯,如加载中,加载失败,⽆数据,⽹络超时,占位图,登录失效等常⽤页⾯。可配合⽹络加载框架,结合返回状态码,错误码,数据进⾏状态页⾃动切换,封装使⽤效果更佳。
本⽂前⾯是使⽤流程,后⾯是原理解析,如果⼤家有兴趣,可耐⼼看完。
效果预览
in Activity in View in Fragment Placeholder Muitl-Fragment ViewPage+Fragment
使⽤场景
下⾯为⼤家常见的加载反馈页⾯:
loading error timeout
empty custom placeholder
⾯对这么多状态页⾯,你是不是还在⽤include的⽅式,setVisibility(View.VISIBLE/GONE),这种⽅式即不⽅便控制,也造成了视图层级冗余(你要把所有状态布局include进⼀个视图)。如果有⼀种⼯具,能把这些事都做了就好了。恰好, LoadSir 把这些事做了,接下来我们就来了解⼀下它。
LoadSir的功能及特点
⽀持Activity,Fragment,Fragment(v4),View状态回调
适配多个Fragment切换,及Fragment+ViewPager切换,不会状态叠加或者状态错乱
利⽤泛型转换输⼊信号和输出状态,可根据⽹络返回体的状态码或者数据返回⾃动适配状态页,实现全局⾃动状态切换
只加载唯⼀⼀个状态视图,不会预加载全部视图
可设置重新加载点击事件(OnReloadListener)
可⾃定义状态页(继承Callback类)
可在⼦线程直接切换状态
可设置初始状态页(常⽤进度页作为初始状态)
不需要设置枚举或者常量状态值,直接⽤状态页类类型(xxx.class)作为状态码
可扩展状态页⾯,在配置中添加⾃定义状态页
可对单个状态页单独设置点击事件,根据返回boolean值覆盖或者结合OnReloadListener使⽤,如⽹络错误可跳转设置页
可全局单例配置,也可以单独配置
⽆预设页⾯,低耦合,开发者随⼼配置
开始使⽤LoadSir
LoadSir的使⽤只需要简单的三步,三步上篮的三步。
添加依赖
compile 'com.kingja.loadsir:loadsir:1.2.0'
第⼀步:配置
全局配置⽅式
全局配置⽅式,使⽤的是单例模式,即获取的配置都是⼀样的。可在Application中配置,添加状态页,设置初始化状态页,建议使⽤这种配置⽅式。
public class App extends Application {
@Override
public void onCreate() {
LoadSir.beginBuilder()
.addCallback(new ErrorCallback())//'添加各种状态页
.addCallback(new EmptyCallback())
.addCallback(new LoadingCallback())
.addCallback(new TimeoutCallback())
.addCallback(new CustomCallback())
.setDefaultCallback(LoadingCallback.class)//设置默认状态页
mit();
}
}
单独配置⽅式
如果你即想保留全局配置,⼜想在某个特殊页⾯加点不同的配置,可采⽤该⽅式。
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new LoadingCallback())
.addCallback(new EmptyCallback())安吉丽娜 朱莉
.
addCallback(new ErrorCallback())
.build();
loadService = ister(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}
});
第⼆步:注册
在Activity中使⽤
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.activity_content);
// Your can change the callback on sub thread directly.
LoadService loadService = Default().register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}
});
春节最佳旅游地点
}}
在View 中使⽤
ImageView imageView = (ImageView) findViewById(R.id.iv_img);
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new TimeoutCallback())
.setDefaultCallback(LoadingCallback.class)
.build();
loadService = ister(imageView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
loadService.showCallback(LoadingCallback.class);
// 重新加载逻辑
}
});
在Fragment 中使⽤
由于Fragment添加到Activitiy⽅式多样,⽐较特别,所以在Fragment中注册⽅式不同于上⾯两种,⼤家先看模板代码:
@Nullable
@Override
郑水晶public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle
savedInstanceState) {
//第⼀步:获取布局View
rootView = View.inflate(getActivity(), R.layout.fragment_a_content, null);
//第⼆步:注册布局View
LoadService loadService = Default().register(rootView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}
山西省长治市邮编
});
//第三步:返回LoadSir⽣成的LoadLayout
LoadLayout();
}
第三步:回调
直接回调
protected void loadNet() {
// 进⾏⽹络访问...
// 进⾏回调
loadService.showSuccess();//成功回调
loadService.showCallback(EmptyCallback.class);//其他回调
}
转换器回调 (推荐使⽤)
如果你不想再每次回调都要⼿动进⾏的话,可以选择注册的时候加⼊转换器,可根据返回的数据,适配对应的回调。
LoadService loadService = Default().register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}}, new Convertor<HttpResult>() {
@Override
public Class<? extends Callback> map(HttpResult httpResult) {
Class<? extends Callback> resultCode = SuccessCallback.class;
switch (ResultCode()) {
case SUCCESS_CODE://成功回调
if (Data().size() == 0) {
resultCode = EmptyCallback.class;
}else{
resultCode = SuccessCallback.class;
太多的借口太多的理由是什么歌
}
break;
case ERROR_CODE:
resultCode = ErrorCallback.class;
break;
}
return resultCode;
}
});
回调的时候直接传⼊转换器指定的数据类型。
loadService.showWithConvertor(httpResult);
⾃定义回调页
LoadSir为了完全解耦,没有预设任何状态页,开发者根据需求⾃定义⾃⼰的回调页⾯,⽐如加载中,没数据,错误,超时等常⽤页⾯,设置布局及⾃定义点击逻辑
public class CustomCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_custom;
}
@Override
protected boolean onRetry(final Context context, View view) {
//布局点击事件
Toast.ApplicationContext(), "Hello mother fuck! :p", Toast.LENGTH_SHORT).show();
//⼦控件事件
(view.findViewById(R.id.iv_gift)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.ApplicationContext(), "It's your gift! :p", Toast.LENGTH_SHORT).show();
病是什么}
});
return true;//返回true则覆盖了register时传⼊的重试点击事件,返回false则两个都执⾏
}
}
代码混淆
-dontwarn com.kingja.loadsir.**
-keep class com.kingja.loadsir.** {*;}
占位图布局效果
placeholder效果状态页类似的效果. LoadSir只⽤了⼀个⾃定义状态页PlaceHolderCallback就完成类似的效果,是不是很棒 :p
看到这,想必各位使⽤LoadSir应该没问题了,如果还想再进⼀步了解它的内部结构,可以继续往下看。
原理解析
流程图
关键类
LoadSir:提供单例模式获取全局唯⼀实例,内部保存配置信息,根据配置创建LoadService。
LoadService:具体操作服务类,提供showSuccess,showCallback,showWithCoverator等⽅法来进⾏状态页回调。
LoadLayout:最终显⽰在⽤户⾯前的视图View,替换了原布局,是LoadService直接操作对象,要显⽰的状态页的视图会被添加到LoadLayout上。
Callback:状态页抽象类,抽象⾃定义布局和⾃定义点击事件两个⽅法留给⼦类实现。
Coverator:转换接⼝,可将⽹络返回实体转换成对应的状态页,达到⾃动适配状态页的⽬的。
我们直接观察在Activity中普通加载和使⽤LoadSir加载视图的区别
>>>没使⽤LoadSir
>>>使⽤LoadSir
⼤家可以看到,LoadSir⽤LoadLayout把原来的布局给替代掉了,原来的布局加在了LoadLayout上,其它⾃定义的状态页也同样会被加到这个LoadLayout上(显⽰的时候),⽽且LoadLayout的⼦View只有⼀个,就是当前要显⽰的状态页布局,并没有把当前不显⽰的⽐如加载中布局,错误布局,⽆数据布局加载进来,这也是LoadSir的优点之⼀,按需加载,并且只加载⼀个状态布局。