首先感谢KingJA提供的第三方库LoadSir,项目地址为:https://github.com/KingJA/LoadSir
LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面, 可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,如占位图,登录失效等常用页面。可配合网络加载框架,结合返回 状态码,错误码,数据进行状态页自动切换,封装使用效果更佳。
LoadSir的功能及特点
支持Activity,Fragment,Fragment(v4),View状态回调
适配多个Fragment切换,及Fragment+ViewPager切换,不会布局叠加或者布局错乱
利用泛型转换输入信号和输出状态,可根据网络返回体的状态码或者数据返回自动适配状态页,实现全局自动状态切换
无需修改布局文件
只加载唯一一个状态视图,不会预加载全部视图
大致效果如下:
不需要设置枚举或者常量状态值,直接用状态页类类型(xxx.class)作为状态码
可对单个状态页单独设置点击事件,根据返回boolean值覆盖或者结合OnReloadListener使用,如网络错误可跳转设置页
无预设页面,低耦合,开发者随心配置
可保留标题栏(Toolbar,titile view等)
可设置重新加载点击事件(OnReloadListener)
可自定义状态页(继承Callback类)
可在子线程直接切换状态
可设置初始状态页(常用进度页作为初始状态)
可扩展状态页面,在配置中添加自定义状态页
可全局单例配置,也可以单独配置
首先我们需要在项目中添加相关依赖:compile'com.kingja.loadsir:loadsir:1.2.2
第一步:配置
全局配置方式
全局配置方式,使用的是单例模式,即获取的配置都是一样的。可在Application中配置,添加状态页,设置默认状态页
public class MyApp extends Application{
@Override
public void onCreate() {
super.onCreate();
LoadSir.beginBuilder().addCallback(new ErrorCallback())
.addCallback(new EmptyCallback())
.addCallback(new LoadingCallback())
.addCallback(new TimeoutCallback())
.addCallback(new CustomCallback())
.setDefaultCallback(LoadingCallback.class)
.commit();
}}
单独配置方式
如果你即想保留全局配置,又想在某个特殊页面加点不同的配置,可采用该方式。
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new LoadingCallback())
.addCallback(new EmptyCallback())
.addCallback(new ErrorCallback())
.build();
loadService = loadSir.register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}
});
第二步:注册
在Activity中使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content);
// Your can change the callback on sub thread directly.
LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加载逻辑
}
});}}
这里需要注意,register中有两个参数,这里看第一个参数,第一个为Object,通常我们这里是我们要展示状态视图的View。
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(setLayoutId(), container, false);
initView();
mBaseLoadService = LoadSir.getDefault().register(mRootView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
onNetReload(v);
}
});
return mBaseLoadService.getLoadLayout();
}
当然,我们也可以是指定的某个View,假设在Fragment中只有某个控件是需要获取数据,并且该控件并没有占满整个布局,那么我们也可以把第一个参数设置为指定的控件。
ImageView imageView = (ImageView) findViewById(R.id.iv_img);
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new TimeoutCallback())
.setDefaultCallback(LoadingCallback.class)
.build();
loadService = loadSir.register(imageView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
loadService.showCallback(LoadingCallback.class);
// 重新加载逻辑
}});
使用还是非常简单的,这里需要注意,我们所有的CallBack都是自定义的,所有的状态视图都由我们自己来定义,只需要继承CallBack,重写onCreateView方法即可。
加载中callBack
public class LoadingCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_loading }}
超时CallBack
public class TimeoutCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_timeout;
}
@Override
protected boolean onRetry(Context context, View view) {
Toast.makeText(context.getApplicationContext(),"Connecting to the network again!",Toast.LENGTH_SHORT).show();
return false;
}}
出错callBack
public class ErrorCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_error;
}}
无数据CallBack:
public class EmptyCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_empty;
}}
自定义CallBack:
public class CustomCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_custom;
}
@Override
protected boolean onRetry(final Context context, View view) {
Toast.makeText(context.getApplicationContext(), "Hello buddy, how r u! :p", Toast.LENGTH_SHORT).show();
(view.findViewById(R.id.iv_gift)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context.getApplicationContext(), "It's your gift! :p", Toast.LENGTH_SHORT).show();
}
});
return true;
}}
知道了如何使用LoadSir之后,我们就要将它构建到我们的基类BaseFragment当中了。
为了避免重复创建Fragment,以及数据的重复加载,我们通常会使用懒加载方式来解决这一问题。这里我就直接贴代码了,注释得非常清楚,无非就是判断当然Fragment是否可见,可见的话并且是第一次才加载数据。
public abstract class BaseFragment extends Fragment{
public Context mContext;
protected View mRootView;
protected LoadService mBaseLoadService;
/**
* 是否为可见状态
*/
private boolean isVisible;
/**
* 是否视图加载完成(第一次加载)
*/
private boolean isPrepared;
/**
* Fragment生命周期中,在执行完onAttach之后就可以获取到上下文了
* @param savedInstanceState
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(setLayoutId(), container, false);
initView();
mBaseLoadService = LoadSir.getDefault().register(mRootView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
onNetReload(v);
}
});
return mBaseLoadService.getLoadLayout();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isPrepared = true;
lazyLoad();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//如果可见
if (getUserVisibleHint()){
isVisible = true;
onVisible();
}else {
isVisible = false;
onInvisible();
}
}
/**
*可见做懒加载
*/
private void onVisible(){
lazyLoad();
}
private void lazyLoad(){
if (!isVisible || !isPrepared){
return;
}
initData();
isPrepared = false;
}
/**
* 不可见时做一些销毁操作
*/
protected void onInvisible(){}
/**
* 初始化控件
*/
public abstract void initView();
/**
* 绑定布局
*/
protected abstract int setLayoutId();
/**
* 初始化数据
*/
protected abstract void initData();
/**
* 重新加载
* @param v
*/
protected abstract void onNetReload(View v);}
基类还是非常简单的,我们可以根据自己的业务需求自行拓展,比如加入Toast等。
那么我们Fragment中的代码就非常简单了,为了更好的展示效果,我们在初始化数据时,模拟网络请求失败,在onNetReload方法中模拟请求成功。
public class OneFragment extends BaseFragment {
@Override
public void initView() {
}
@Override
protected int setLayoutId() {
return R.layout.view1;
}
@Override
protected void initData() {
PostUtil.postCallbackDelayed(mBaseLoadService, ErrorCallback.class);
}
@Override
protected void onNetReload(View v) {
Toast.makeText(getContext(),"reload in Fragment A",Toast.LENGTH_SHORT).show();
mBaseLoadService.showCallback(LoadingCallback.class);
PostUtil.postSuccessDelayed(mBaseLoadService);
}}
本文到此基本可以结束了,毕竟标题是BaseFragment,再说就跑题了!!!至于TabLayoyut和ViewPager结合Fragment的使用我这里就不介绍了。
这里把文章中设计到的一些资源文件放出来给大家。