打造一个高效易用的懒加载BaseFragment

首先感谢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的使用我这里就不介绍了。

这里把文章中设计到的一些资源文件放出来给大家。

timeout.png
custom.png
empty.png
img.jpg
music.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,242评论 25 708
  • LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态...
    KingJA阅读 15,856评论 69 125
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,914评论 18 139
  • 作者介绍冯宇飞 ,现任人人车Android客户端架构师。 本文回顾总结了人人车公司Android客户端的架构演进历...
    passiontim阅读 1,580评论 0 9
  • 终于考完了计算机,算是了却了一件大事。姑娘松口气,然后继续努力。为了成为更优秀的自己。
    9a63a67e192b阅读 56评论 0 1