商城项目实战 | 15.1 实现分页工具类的封装

本文为菜鸟窝作者刘婷的连载。”商城项目实战”系列来聊聊仿”京东淘宝的购物商城”如何实现。

在之前的文章《商城项目实战 | 6.2 OkHttp 轻松封装 更加灵活的调用》和文章《商城项目实战 | 9.1 Adapter 封装的全面解析》中已经详细讲解了 OKHttp 网络框架的封装和 Adapter 适配器的封装,随着商城项目的不断推进,特别是在商城项目中列表的下拉刷新和上拉加载更多在很多的功能模块中都有涉及,为了更好的开发和维护代码,需要把列表的分页工具类单独封装起来,也就有了本文对于分页工具类封装的讲解了。

封装的分页工具类所要实现的功能

每一次的开发是为了更好地方便我们的生活,而每一次的封装是为了更好的开发,那么对于分页工具类,我们希望它具备怎样的功能呢,我们先来分析下,下面是我罗列的分页工具类所要实现的功能。

  1. 1.实现基本的下拉刷新和上拉加载更多功能。
  2. 2.简洁的 API 调用,对于加载、刷新和加载更多事件的监听扩展。
  3. 3.刷新控件、url、参数等是可变的,可以传入到分页工具类中,根据不同的传入值来做处理。
  4. 4.分页工具的创建和调用方法最好简单化。
  5. 5.刷新控件的属性是可扩展的,比如是否可以上拉加载更多是可以设置的。
  6. 6.每次加载多少条数据、请求的数据类型这些都是可以简单设置的。
  7. 7.对于异常的处理最好都封装好,调用时不必过多考虑。

按照上面的这些要求,下面开始实现分页工具类的封装。

封装分页工具类

工具类的简单创建和调用可以节省很多不必要的麻烦,那么首先就是写好分页工具类的创建方法。

1. 分页工具类的创建和调用

封装的分页工具类需要可以简单的创建,同时还要可以设置相关的一些属性,这里就先创建工具类 Pager 和一个静态类 Builder,其中静态类 Builder 用于工具类属性的设置和创建,先在里面写入初始化 Builder 的方法。

 public static Builder newBuilder() {

        builder = new Builder();
        return builder;
    }

这里 new 了一个 Builder,初始化 Builder 完成,还要初始化 Pager 分页工具类。

private Pager() {

        httpHelper = OkHttpHelper.getInstance();

    }

分页工具类和静态类的初始化完成,就可以开始写创建的方法。

 public Pager build(Context context, Type type) {

            this.mType = type;
            this.mContext = context;

            return new Pager();

        }

这里的 Context 不必多说就是 Context 上下文,而 Type 就是数据的类型,传入 Context 和 Type,可以根据在不同地方的使用和不同数据类型的请求来创建所需的分页工具类。

2. 异常的捕获

在使用分页工具类的时候,分页工具类内部的处理不必过多的处理,只要在外面简单创建,然后调用相应的方法就好,在创建的过程中可能出现传入的所需参数少了的问题,这时候就会出现异常,这个异常我们在外面调用时肯定不想多管,最好是封装的分页工具类内部就要处理,处理如下。

private void valid() {

            if (this.mContext == null)
                throw new RuntimeException("context can't be null");

            if (this.mUrl == null || "".equals(this.mUrl))
                throw new RuntimeException("url can't be  null");

            if (this.mRefreshLayout == null)
                throw new RuntimeException("MaterialRefreshLayout can't be  null");
        }

异常的处理最好是放在之前写好的 build(Context, Type)方法内,在创建的时候就捕获到,这样在外面调用时也知道哪里出了具体的什么问题。

3. 设置分页工具类的相关属性方法

作为列表的分页工具类,每次列表所要加载的数据量、网络请求的 URL、是否可以上拉加载更多、设置网络请求参数等这些属性自然是要可以在外面创建时进行对应的设置,所以在封装的时候也要提供对应的设置方法。

 public Builder setPageSize(int pageSize) {
            this.pageSize = pageSize;
            return builder;
        }

这是用于设置每次加载数据量的方法,同样的还可以写设置 URL 的方法。

public Builder setUrl(String url) {

            builder.mUrl = url;

            return builder;
        }

这些相关属性设置的方法都应在分页工具类创建时一起设置,所以返回的都是静态类 Builder,这里封装了分页工具类的相关属性,其他属性的设置方法都是一样的,都写在静态类 Builder 中就好。

4. 添加事件监听

分页中涉及的主要事件分为加载、刷新和加载更多,事件监听的添加只要写好接口即可。

public interface  OnPageListener<T>{

        void load(List<T> datas,int totalPage,int totalCount);

        void refresh(List<T> datas,int totalPage,int totalCount);

        void loadMore(List<T> datas,int totalPage,int totalCount);

    }

load(List<T> datas,int totalPage,int totalCount) 是数据加载事件,refresh(List<T> datas,int totalPage,int totalCount) 是刷新数据事件,而 loadMore(List<T> datas,int totalPage,int totalCount) 则是加载更多事件。

5. 请求数据

事件监听已经写好了,这里所用的是 OkHttp 请求网络数据,而之前也已经封装好了 OkHttp,请求数据就很简单了。

 private void requestData() {

        String url = buildUrl();

        httpHelper.get(url, new RequestCallBack(builder.mContext));

    }

RequestCallBack 是数据请求回调方法,网络数据请求成功、失败、出错的处理都写在这里。

class RequestCallBack<T> extends SpotsCallBack<PageInfo<T>> {

        public RequestCallBack(Context context) {
            super(context);

            super.mType = builder.mType;
        }

        @Override
        public void onFailure(Request request, Exception e) {

           //数据请求失败的处理

        }

        @Override
        public void onSuccess(Response response, PageInfo<T> page) {

            //数据请求成功的处理
        }

        @Override
        public void onError(Response response, int code, Exception e) {

            //错误处理

        }
    }

PageInfo 是分页的实体类,在商城项目中是通用的,有 currentPage 当前页,pageSize 页面数据量,totalPage 总共的页面数以及 totalCount 总数量四个属性,而传入的 Type 是数据类型。

6. 显示数据

数据请求完成之后,就要显示在列表中,在不同的状态下,显示数据的处理也不同,状态有三种,分为 STATE_NORMAL 一般状态,STATE_REFRESH 刷新状态和 STATE_MORE 加载更多状态。

 private <T> void showData(List<T> datas, int totalPage, int totalCount) {

        if (STATE_NORMAL == state) {

            builder.mRefreshLayout.setLoadMore(builder.canLoadMore);
            if (datas == null || datas.size() <= 0) {
                ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.can_not_load_data), 2500);
            }

            if (builder.onPageListener != null) {
                builder.onPageListener.load(datas, totalPage, totalCount);
            }

        } else if (STATE_REFRESH == state) {

            builder.mRefreshLayout.setLoadMore(builder.canLoadMore);
            if (datas == null || datas.size() <= 0) {
                ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.can_not_load_data), 2500);
            }

            builder.mRefreshLayout.finishRefresh();
            if (builder.onPageListener != null) {
                builder.onPageListener.refresh(datas, totalPage, totalCount);
            }

        } else if (STATE_MORE == state) {

            if(datas.size()<= 0){
                ToastUtils.show(builder.mContext, builder.mContext.getString(R.string.not_more_data), Toast.LENGTH_SHORT);
                builder.mRefreshLayout.finishRefreshLoadMore();
                builder.mRefreshLayout.setLoadMore(false);
            }else{
                builder.mRefreshLayout.finishRefreshLoadMore();
                if (builder.onPageListener != null) {
                    builder.onPageListener.loadMore(datas, totalPage, totalCount);
                }
            }

        }
    }

STATE_NORMAL 一般状态时,有数据就调用加载数据方法 load(List<T> datas,int totalPage,int totalCount),没有数据就提示无相关数据,STATE_REFRESH 刷新状态时,有数据就调用刷新数据方法 refresh(List<T> datas,int totalPage,int totalCount),没有则是提示无相关数据,而 STATE_MORE 加载更多时,有数据就调用加载更多数据方法 loadMore(List<T> datas,int totalPage,int totalCount),无数据则提示没有更多的数据。

实现可以下拉刷新和加载更多的热门商品列表

在文章《商城项目实战 | 8.2 SwipeRefreshLayout 实现可以下拉刷新和加载更多的热门商品列表》中详细介绍了如何实现可以下拉刷新和加载更多的热门商品列表,现在封装好了分页工具类后,我们直接使用工具类来实现。

1. 创建分页工具类

在原来的代码中创建分页工具类,分页工具类在创建时需要设置对应的相关属性,在这里就这样设置。

Pager pager = Pager.newBuilder()
                .setUrl(Constants.API.WARES_HOT)
                .setLoadMore(true)
                .setOnPageListener(this)
                .setPageSize(10)
                .setRefreshLayout(layoutRefresh)
                .build(getContext(), new TypeToken<PageInfo<WaresInfo>>() {}.getType());
        pager.request();

设置了 网络请求的 URL 为 Constants.API.WARES_HOT,控件可以加载更多,事件监听,每次请求的数据量为10,所要使用的列表控件为 layoutRefresh 以及数据类型,最后调用 request() 方法进行网络数据请求。

2. 实现加载事件

在创建分页工具类时设置了事件监听,我们在热门模块中就要实现其中的加载、刷新和加载更多三个事件,先实现加载事件。

@Override
    public void load(List<WaresInfo> datas, int totalPage, int totalCount) {
        mAdatper = new HWAdapter(getContext(),datas);


        recyclerView.setAdapter(mAdatper);

        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
    }

新建 HWAdapter 商品适配器,并且初始化好 recyclerView 列表控件的属性,并且为 recyclerView 列表控件添加 Adapter。

3. 实现刷新事件

刷新事件的实现很简单,就是要刷新数据,然后列表滑动到最顶部就行了。

 @Override
    public void refresh(List<WaresInfo> datas, int totalPage, int totalCount) {
        mAdatper.refreshData(datas);

        recyclerView.scrollToPosition(0);
    }

refreshData() 为 Adapter 中数据刷新方法,这里直接调用了。

4. 实现加载更多事件

加载更多就是在原来的列表中在后面添加新的数据,所以实现也很简单。

    @Override
    public void loadMore(List<WaresInfo> datas, int totalPage, int totalCount) {
        mAdatper.loadMoreData(datas);
        recyclerView.scrollToPosition(mAdatper.getDatas().size());
    }

loadMoreData() 方法是 Adapter 中的添加数据的方法,在加载更多事件中就是实现数据的增加以及列表滑动到数据的添加处。

5. 实现效果

使用封装好的分页工具实现可以下拉刷新和加载更多的热门商品列表一下子就变得简单了,最后运行代码,获取最终效果。

效果图
效果图

撸这个项目的一半,你就是大神 , 戳http://mp.weixin.qq.com/s/ZagocTlDfxZpC2IjUSFhHg

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,258评论 25 707
  • 谈到我们炎热的夏天,大家所期待的而是暑假和那一根根冰凉的冰棒吧。 我们毕业了,男生女生抢着表白。大人总是说,我们...
    盛夏的离别阅读 279评论 0 1
  • 其实呢 只是他用同样的态度与方式对待我 我就有些不舒服了 想想之前 我不是一样的累了就跟他说我先睡了 你继续嗨吗...
    Arc空有少女心阅读 162评论 0 0
  • 真快啊,一晃这是我们第五个月了,首先要感谢亲爱的你,你的不离不弃才让我今天能够写下这篇文章。 过去的四个月里,我们...
    为你写书阅读 220评论 0 0
  • 初学请多指教
    琼菟阅读 154评论 0 1