电子市场总结(二)

电子市场总结(二)

1、封装一个LoadingPager

什么是LoadingPager?

在项目中我们可以看到,大多数页面都有五种情况发生

  1. 未加载
  2. 正在加载(转圈的那种)
  3. 加载成功了
  4. 加载失败了
  5. 加载成功但是没有任何数据

可以想象,我们的项目中需要大量的去构建这样的界面,如果我们简单只是将每个状态对应的页面先写完整,再在每一个Fragment中整合那样的工作量很大,而且不易维护。

此时为了适应这种大规模使用的现象,我们利用一个具备五种状态的FrameLayout来简化这些操作。

自定义LoadingPager的详细解释

1.自定义一个FrameLayout,命名为LoadingPager
2.五种数据加载的状态
public static final int 
    STATE_EMPTY = 0, // 未加载
    STATE_ERROR = -1, // 加载失败
    STATE_SUCCESS = 1, // 加载成功
    STATE_LOADING = 2, // 正在加载(转圈的那种)
    STATE_NO_DATA = -2; // 没有加载到数据(加载成功的第二种状态)

同时五种状态对应五种布局

private View mEmptyLayout, // 空布局
    mErrorLayout, // 错误布局
    mLoadLayout, // 加载中布局
    mNoDataLayout, // 未加载到数据的布局
    mSuccessLayout; //成功的布局,由调用者自定义
3.加载成功的布局

1.控制显示

可以看出LoadingPager虽然可以封装这些状态,并且可以根据不同的状态展示不同的布局,但是这些布局仍然可以自定义,并由调用者根据自己的需求更换对应状态的布局。
因此可以暴漏一些方法来让调用者去自定义这些布局。此处仅对成功的布局进行了拓展,当我们的状态变为 STATE_SUCCESS 时,切换成调用者提供的布局。代码如下

/**
 * 展示当前的状态对应的布局,隐藏其他布局
 */
private void showCurrentLayout() {
    mEmptyLayout.setVisibility(currentState == STATE_EMPTY ? VISIBLE : GONE);

    mErrorLayout.setVisibility(currentState == STATE_ERROR ? VISIBLE : GONE);

    mLoadLayout.setVisibility(currentState == STATE_LOADING ? VISIBLE : GONE);

    mNoDataLayout.setVisibility(currentState == STATE_NO_DATA ? VISIBLE : GONE);

    // 加载 数据成功 且是在布局初次加载的状态
    if (currentState == STATE_SUCCESS && mSuccessLayout == null) {
        mSuccessLayout = initSuccessLayout();
        // 所加载的布局不能为空
        if (mSuccessLayout != null)
            addView(mSuccessLayout);
    }
    // 当加载成功的布局成功设置后,对其状态进行判断
    if (mSuccessLayout != null)
        mSuccessLayout.setVisibility(currentState == STATE_SUCCESS ? VISIBLE : GONE);
}

通过使用抽象方法的形式,强制要求调用者去实现加载成功的布局

2.控制当前状态

提供设置状态的方法,让调用者可以在自己想要的时间里去展示成功的布局

/**
 * 设置Loadingpager当前的状态
 *
 */
public void setCurrentState(int state) {
    // 先判断当前结果是否为空
    this.currentState = state;
    showCurrentLayout();
}

3.重新加载的方法

暴漏一个可以设置重新加载事件的方法

public void setOnReloadClickListener(OnClickListener cl){
    btn_load_again.setOnClickListener(cl);
}

2、封装一个BaseFragment

1.为什么还要封装一个BaseFragment?

在前面我们已经封装了一个LoadingPager,我们可以很方便的控制这个自定义view去设置当前的状态和布局。

那么这个view应该在那里显示呢?view本身不能去控制当前的状态,调用者控制其显示的逻辑又在哪里呢?

提出这两个问题的同时,我们还要考虑,这么多的fragment他们都要用到LoadingPager因此我们应将这个两个问题的解决方法统一的封装起来,在一个BaseFragment中去处理,其他想要使用这种LoadingPager模式的Fragment只要继承BaseFragment就可以只关心自己的数据加载和界面展示了。

2.具体的封装

1.onCreateView中去展示LoadingPager,同时要求子类实现initSuccessLayout()方法来设置加载成功的布局,因为BaseFragment虽然实现了LoadingPager,但是他仍然需要将这个问题交给子类。

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    //统一使用自定义的具备状态的loadingpager
    mRootLayout = new LoadingPager(mActivity) {
        @Override
        public View initSuccessLayout() {
            mSuccessLayout = BaseFragment.this.initSuccessLayout();
            return mSuccessLayout;
        }
    };
    //设置重新加载的监听器
    mRootLayout.setOnReloadClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            loading();
        }
    });

    return mRootLayout;
}

2.同时我们可以将Activity在BaseFragment中拿出来,这样子类可以直接使用

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.mActivity = getActivity();
}

3.加载数据的逻辑

这里考虑到所有的数据加载都需要IO处理或者是通过网络来加载,那么可以BaseFragment里使用子线程这件事统一包办了,子类只需要完成 loadData() 方法返回他的加载状态即可。子类来返回加载状态的原因是,BaseFragment并不知道是怎么去加载的,所以这个逻辑仍然要抛给子类。

/**
 * BaseFragment统一具备的加载方法,子线程加载
 */
public void loading() {
    // 考虑到大多数的加载过程都是请求网络,所以采用子线程
    ThreadManager.ThreadPool instance = ThreadManager.getInstance();
    instance.execute(new Runnable() {
        @Override
        public void run() {
            // 子类加载后返回对应的状态,如何去控制显示的问题父类来解决即可
            final BaseFragment.State state = loadData();
            // 设置loadingpager的状态
            UIUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (mRootLayout != null && state != null)
                        mRootLayout.setCurrentState(state.getState());
                }
            });
        }
    });
}

4.为子类中对数据的加载成功与否提供一个默认的判断

/**
 * 提供给子类进行检查初次加载成功与否
 *
 */
protected State checkLoad(List list) {
    if (list != null) {
        if (list.size() == 0)
            return State.STATE_NO_DATA;
        else
            return State.STATE_SUCCESS;
    }
    return State.STATE_ERROR;
}

5.重新加载的逻辑,即对重新加载的按钮设置点击事件

//设置重新加载的监听器
mRootLayout.setOnReloadClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        loading();
    }
});

6.总结,子类需要完成这些事情

  1. protected abstract View initSuccessLayout(); // 加载成功后是什么样的布局
  2. protected abstract State loadData(); // 加载数据的逻辑
  3. protected abstract void initListener(); // 监听的初始化

封装完成后的效果如下:

3、其他的知识点

1.枚举的用法

枚举他实际相当于一个变相的class类,他可以设置构造器,但是他的主要目的还是定一些不会被改变的值,如下将LoadingPager对应的状态进行了封装,那么子类在加载数据的时候就可以只返回枚举值而不是int数值了:

/**
 * 枚举的用法
 */
public static enum State {
    STATE_ERROR(LoadingPager.STATE_ERROR),
    STATE_LOADING(LoadingPager.STATE_LOADING),
    STATE_SUCCESS(LoadingPager.STATE_SUCCESS),
    STATE_NO_DATA(LoadingPager.STATE_NO_DATA);

    int state;
    // 枚举的构造器实际上只能自己使用,可以通过这种方式,为自己设置数据
    State(int state) {
        this.state = state;
    }

    // 获取枚举存储的数据,调用者可以通过get方式去获取这个数据
    int getState() {
        return state;
    }
}

4、封装思想的总结

LoadingPager和BaseFragment的封装抽取思想仅仅是整个项目的开始,其中LoadingPager是对布局显示的封装,BaseFragment是对如何使用LoadingPager和控制LoadingPager的封装。
通过这两层封装,子类所有集成自BaseFragment的对象只需要关心自己要显示什么和数据的加载即可。

在这里并没有涉及任何新的知识点,而是基本的封装思想的搭建。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值