Android页面加载神器Loader

背景:

一般我们开发android app的时候,最经常遇到的一个情况就是处理各种各样的页面加载状态,如:加载中,加载失败,数据为空。
而一般我们的做法有写个BaseActivity,在这里面放处理各种状态,如果有遇到Fragment,则又需要写个BaseFragment,之后,我们又要根据加载的结果,去显示相应的状态。
如果是列表数据,则又会写出一个BaseListActivity之类的,如果有新的需求,则又会冒出新的Base类。
当然,本人并不是说这么写不行。只是这么写重复代码之多,扩展性也不好,对于一个严格遵守KISS准则的人而言,苦不堪言。

解决

既然上面有这种问题,那我们应该怎么处理呢,首先要明确的是,一个app,他的加载状态,一般而言只有一套,特殊页面可能需要特殊处理。针对这点,我想到的是,写一个ILoadStateHelper接口,单纯用以控制页面加载状态:

public interface ILoadStateHelper {

    /**
     * 显示内容视图
     */
    void showContent();

    /**
     * 显示加载中视图
     */
    void showLoading();

    /**
     * 显示空界面视图
     */
    void showEmpty();

    /**
     * 显示错误视图
     */
    void showError(boolean isEmpty,Throwable t);

    /**
     * 重新加载监听
     *
     * @param listener
     */
    void setReloadListener(OnReloadListener listener);
}

之后呢,单单这点还不够,一般页面也有刷新功能,为了处理刷新,写一个IRefreshHelper接口:

public interface IRefreshHelper {

    /**
     * 刷新完成
     *
     * @param isSuccess 是否加载成功
     */
    void refreshComplete(boolean isSuccess);

    /**
     * 设置刷新监听
     *
     * @param listener 刷新监听
     */
    void setOnRefreshListener(OnRefreshListener listener);

    /**
     * 是否在刷新中
     *
     * @return true:刷新,false:不刷新
     */
    boolean isRefreshing();
}

再然后,就是处理列表数据了,这里要做的事情就比较多了,其实主要就是控制自动加载下一页,写一个IListViewHelper:

public interface IListViewHelper {

    /**
     * 刷新adapter
     */
    void notifyAdapter();

    /**
     * 显示空闲状态
     */
    void showLoadMoreIdle();

    /**
     * 显示加载中状态
     */
    void showLoadMoreLoading();

    /**
     * 显示无更多状态
     */
    void showLoadMoreNoMore();

    /**
     * 显示错误状态
     */
    void showLoadMoreError();

    /**
     * 设置加载更多监听
     *
     * @param listener 加载更多监听
     */
    void setOnLoadMoreListener(OnLoadMoreListener listener);

    /**
     * 设置重新加载更多监听
     *
     * @param listener 重新加载更多监听
     */
    void setOnReLoadMoreListener(OnReloadListener listener);

    /**
     * 是否加载更多
     *
     * @return 是否加载更多
     */
    boolean isLoadingMore();
}

这几个helper,可以处理常见的页面加载逻辑,一般而言,一个app,我们只要定好BaseLoadStateHelper,BaseRefreshHelper,BaseListViewHelper,就可以在每个页面中使用了。

然后下面才是重头戏,配合我标题中所说的Loader,加载的相关逻辑全部用loader去处理就好了,可以使得页面又清爽,又干净。
那么什么是Loader呢,Loader是用来加载数据的一个工具类,它需要配合Model来使用,Model是Activity对应页面的数据模型,Loader通过Model去加载数据,并根据Model的数据是否为空,以及根据上面几个helper,显示相应的界面。
这里的代码量相对就比较多,故就不贴出来了。

使用:

Loader的使用非常的简便。
首先你需要将你的BaseActivity这么去写

public class BaseActivity extends AppCompatActivity implements INetworkView {

    private DataLoader mLoader;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        destroyLoader();
    }

    @Override
    public void destroyLoader() {
        if (mLoader != null) {
            mLoader.onDestroy();
        }
    }

    @Override
    public void setDataLoader(DataLoader loader) {
        mLoader = loader;
    }
}

这么做是为了在destroy的时候,取消加载,释放内存。
其次,定义好上面的几个helper,
之后,写好Model:

public class SingleDataModel extends Model<String> {

    private String response;

    @Override
    public boolean isEmpty() {
        return TextUtils.isEmpty(response);
    }

    @Override
    public void setData(boolean isRefreshing, String response) {
        this.response = response;
    }

    @Override
    protected Call<String> getModelCall() {
        MainApi api = ApiManager.getInstance().getMainApi();
        return api.getTestCall();
    }
}

或者:

public class ListDataModel extends ListModel<String, String> {

    public ListDataModel(List<String> list) {
        super(list);
    }

    @Override
    protected boolean ensureHasNext(String response, List<String> mapList) {
        return page < 10;
    }

    @Override
    protected List<String> map(String response) {
        List<String> list = new ArrayList<>();
        int size = mList.size();
        for (int i = 0; i < 20; i++) {
            list.add((i + size) + ":XXXXXXXXXXXXXXXXXXXXXXXXXX");
        }
        return list;
    }

    @Override
    protected Call<String> getModelCall() {
        MainApi api = ApiManager.getInstance().getMainApi();
        return api.getTestCall();
    }
}

之后就是在Activity中调用了:

public class SingleDataActivity extends BaseActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_single_data);
        SwipeRefreshLayout layout = (SwipeRefreshLayout) findViewById(R.id.act_single_data_sfl);
        final TextView textView = (TextView) findViewById(R.id.act_single_data_tv);
        SingleDataModel model = new SingleDataModel();
        DataLoader<String> loader = new DataLoader<>(this, model);
        loader.setLoadStateHelper(new LoadStateHelper(layout));
        loader.setRefreshViewHelper(new RefreshHelper(layout));
        loader.setOnLoadSuccessListener(new OnLoadSuccessListener<String>() {
            @Override
            public void onSuccess(boolean isRefreshing, String response) {
                textView.setText(response);
            }
        });
        loader.load();
    }
}

或者

public class ListDataActivity extends BaseActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_list_data);
        SwipeRefreshLayout layout = (SwipeRefreshLayout) findViewById(R.id.act_list_data_sfl);
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.act_list_data_rv);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        List<String> list = new ArrayList<>();
        MyAdapter adapter = new MyAdapter(list);
        recyclerView.setAdapter(adapter);

        ListDataModel model = new ListDataModel(list);
        ListLoader<String, String> loader = new ListLoader<>(this, model);
        loader.setLoadStateHelper(new LoadStateHelper(layout));
        loader.setRefreshViewHelper(new RefreshHelper(layout));
        loader.setListViewHelper(new RecyclerViewHelper(recyclerView));
        loader.load();
    }
}

备注:

Loader是用Retrofit2+Rxjava2。
Loader也可以有缓存作用,本人才疏学浅,不知道如何同http的缓存,去做到在有网络比较慢的情况下,也能先显示缓存的内容,在去服务器端获取,或者判断缓存是否过期再去获取数据。故只能自己写一个拙劣的缓存控制策略,如有好的建议,还希望不吝赐教。

如需实现缓存,则需要在Model中,重写getCacheStrategy方法,如:

public class ListDataModel extends ListModel<String, String> {

    public ListDataModel(List<String> list) {
        super(list);
    }

    @Override
    protected boolean ensureHasNext(String response, List<String> mapList) {
        return page < 10;
    }

    @Override
    protected List<String> map(String response) {
        List<String> list = new ArrayList<>();
        int size = mList.size();
        for (int i = 0; i < 20; i++) {
            list.add((i + size) + ":XXXXXXXXXXXXXXXXXXXXXXXXXX");
        }
        return list;
    }

    @Override
    protected Call<String> getModelCall() {
        MainApi api = ApiManager.getInstance().getMainApi();
        return api.getTestCall();
    }

    @Override
    protected CacheStrategy<String> getCacheStrategy(Request request) {
        return new CacheStrategy<String>(request, CacheStrategy.CacheType.READ_CACHE_UPDATE_UI_THEN_NET, 180) {
            @Override
            public boolean isTimeOut() {
                return false;
            }

            @Override
            public String readCache() {
                return null;
            }

            @Override
            public void saveCache(String s) {

            }
        };
    }
}

至此,Loader的介绍基本结束,没怎么写博文,写的不好,还望大家谅解。

传送门:

Loader

compile 'com.github.linxin6560:loader:1.0.7'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值