打造一个高效易用的懒加载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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

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