上一篇说到谷歌电子市场app的大体框架,重点是怎样填充viewpager,我们使用了一个个Fragment去作为页面的载体,这篇我们将怎样在Fragment中初始化页面。

我们知道,Fragment只是一个View的载体,也就是说View是显示在Fragment中,所以,初始化一个Fragment需要实现onCreateView()方法,返回的View就是显示在Fragment中的页面,因此,我们要编辑一个个的View来作为onCreateView()方法的返回值,而此项目中包含的7个标签页Fragment都是继承BaseFragment,为什么要这么做呢?我们可以用面向对象的思想来思考,上篇提到过,各个标签页显示的View有相似之处。在对网络发出请求时,根据网络状态,页面会显示不同的状态。

1.未加载和没有数据状态。

2.加载失败

3.正在加载

4.加载成功

大致分为五种状态(未加载和没有数据显示相同界面),其中只有加载成功之后页面才会显示从网络中获取到的数据,而其他四种状态各个页面显示的都是相同的View,这就是相似之处,而共同之处可以的父类就进行初始化,子类只需直接继承即可。因此在BaseFragment中,我们可以直接自定义一个View类,去填充它。接下来问题就是,该自定义一个什么View才合适呢?

在开发其他app时,每个Activity几乎都会为它配置一个相应的Layout文件,也就是显示在Activity中的界面,更直白的说,就是填充在Activity中的View,而Layout文件就是布局文件,我们知道,android中有五大布局,LinerLayout(线性布局)、FrameLayout(帧布局)、TableLayout(表格布局)、RelativeLayout(相对布局)、AbsoluteLayout(绝对布局),其中帧布局是五大布局中最简单的一个布局,在这个布局中,整个界面被当成一块空白备用区域,这正是我们需要的,也就相当于在Fragment中放了一块空白的画布,我们只需要在上面画出我们所需要界面效果即可。因此,自定义View可以继承FrameLayout。

新建Loadingpage类,继承FrameLayout,实现三个构造方法。然后在BaseFragment初始化一个LoadingPage对象,将其作为onCreateView()的返回值。

现在画布有了,我们就要开始动手绘画了。

1.考虑到网络加载的五种状态,首先设置一些代表这些状态的标记常量

private static final int STATE_LOAD_UNDO=1;//未加载
private static final int STATE_LOAD_LOADING=2;//加载中
private static final int STATE_LOAD_ERROR=3;//加载失败
private static final int STATE_LOAD_EMPTY=4;//数据为空
private static final int STATE_LOAD_SUCCESS=5;//加载成功

2.开始初始化页面,上面说过,只有加载成功的页面没有相似,其它四种状态我们都可在此类中初始化

(1)对上述四种状态编写相应的布局文件

(2)使用View.inflate()方法,将布局文件转换为一个个的View

(3)调用addView()方法将View添加到FrameLayout中

运行之后,发现在界面中各个状态对应的页面重叠在一起,那么,接下来就需要对各种状态进行判断,来判断何种页面该显示和不该显示。

3.创建一个showRightPage()方法,在此方法中实现判断逻辑

private void showRightPage() {mLoadingEmptyPage.setVisibility((mCurrentState==STATE_LOAD_UNDO||mCurrentState==STATE_LOAD_EMPTY)?VISIBLE:GONE);
    mLoadingErrorPage.setVisibility(mCurrentState==STATE_LOAD_ERROR?VISIBLE:GONE);
    mLoadingPage.setVisibility((mCurrentState == STATE_LOAD_LOADING) ? VISIBLE : GONE);
    if (mLoadingSuccessPage==null&&mCurrentState==STATE_LOAD_SUCCESS){mLoadingSuccessPage = onCreateSuccessPage();
        if (mLoadingSuccessPage!=null){addView(mLoadingSuccessPage);
        }}
}

这个方法主要就是使用View的setVisbility()方法来实现view的显示和隐藏。

再运行之后,发现运行正常,得到我们想要的效果。

现在,我们需要解决的就是加载成功状态页面的初始化,这里逻辑比较绕,需要好好整理思路。

首先,我们知道,每一个Fragment里的加载成功页面是各不相同的,因此,父类中也就是BaseFragment中不能决定各子类的页面的显示效果,换句话说,加载成功页面不能在父类中初始化,那么,该怎样让子类决定该如何加载呢?有没有一种类,是在父类声明,而在子类中实现的呢?

没错,就是抽象类,面向对象的思想告诉我们,我们可以在抽象类中声明抽象方法,继承抽象类的子类必须要实现其父类未实现的抽象方法,这正是我们想要的。

1.将LoadingPage类改为抽象类,在其中添加onCreateSuccessPage()抽象方法,交给其子类实现,因为LoadingPage类不知道该如何初始化加载成功页面,只能交给其子类去实现。由于BaseFragment中初始化了LoadingPage类的对象,因此,也需要实现其抽象方法。

mLoadingPage = new LoadingPage(UIUtils.getContext()){@Override
    public View onCreateSuccessPage() {return null;
    }
};

2.但是,此时又出现了问题,BaseFragment也不知道该如何初始化加载成功页面,所以,我们再将BaseFragment类改为抽象类,创建onCreateSuccessPage()抽象方法,交给各自的标签Fragment去实现。

mLoadingPage = new LoadingPage(UIUtils.getContext()){@Override
    public View onCreateSuccessPage() {return BaseFragment.this.onCreateSuccessPage();
    }
};

现在,我们实现了加载成功页面的初始化,但是,新的问题又出现了,我们知道,加载成功是需要请求数据的,每个页面都需要请求数据,这又是相似之处,那么就可以在父类去初始化

1.在LoadingPage类中创建一个LoadingData()方法,因为要请求网络数据,所以必须开启子线程去加载,而具体如何加载,请求何种网络,以什么方式去请求,LoadingPage都不知道,那么就只有交给其他类去实现,所以需要再创建一个onLoad()抽象方法。在这里还要注意onLoad()的返回值。onLoad()需不需要返回值呢?

此时又要考虑到网络状态的问题,对于请求数据,可能就有三种情况,第一种是最好的,加载成功了,我们获取到了数据,页面正常运行了,第二种呢,就是加载失败,比如说服务器崩溃了,手机没联网,这些情况都可能导致加载失败,一旦加载失败,那么就要回到加载失败状态的页面,第三种,就是数据为空的情况,网络都正常,但是服务器中没有数据提供,那么请求到的数据也就是空的,那么就必须返回到数据为空的状态页面。

既然有网络状态的问题,那么,onLoad()方法就必须要有一个返回值,告诉LoadingData()方法到底有没有接收到数据,以便各个标签页显示相应的加载页面,因为除了加载成功的页面,其他两种状态的页面都在LoadingPage类中初始化,而LoadingData()是在LoadingPage类中的,所以onLoad()方法需要返回值。

那么返回值是什么呢?包含多个数据,我们首先想到的就是一个集合去封装,但是我们又知道,这三种状态需要和上面五种网络状态的标记常量关联起来,这时,就可以想到使用枚举是最好的,枚举中的每一个成员都代表一个对象,我们去实现它的一个带参的构造方法去覆盖默认的构造方法,这个参数就可以设置为int型(因为,代表上述五种网络状态的标记常量是int型的,我需要将标记常量作为参数去和每一个枚举成员关联起来)。

public enum ResultState{STATE_SUCCESS(STATE_LOAD_SUCCESS),STATE_EMPTY(STATE_LOAD_EMPTY),STATE_ERROR(STATE_LOAD_ERROR);
    private int state;
    ResultState(int state){this.state=state;
    }public int getState(){return state;
    }
}

这样一个onLoad()抽象方法就构造完成了。此时,我们在LoadingData中就可以根据onLoad()的返回值去做相应的UI更新,此处还需要注意,因为LoadingData()方法中单独开了一个子线程去实现请求网络数据,而更新UI必须在主线程中实现,这时,UIUtils工具类就体现其作用了,我们在上一篇中就说过,UIUtils中维护了一个RunningMainThread()方法,其作用就是将线程抛给主线程去实现,此处就可以直接调用这个方法,去实现UI更新。

public void LoadingData(){if (mCurrentState!=STATE_LOAD_SUCCESS){mCurrentState=STATE_LOAD_SUCCESS;
        new Thread(new Runnable() {@Override
            public void run() {final ResultState resultState=onLoad();
                UIUtils.RunningMainThread(new Runnable() {@Override
                    public void run() {if (resultState!=null){mCurrentState=resultState.getState();
                        }showRightPage();
                    }});
            }}).start();
    }
}

至此,LoadingData()就已经维护完成。但是,我们也发现这个方法还没有任何调用,那么,在何处调用这个方法呢?

当我们打开应用时,页面就开始请求数据,在滑动ViewPager里的页面时,我们也需要去请求数据,也就是说,当前ViewPager处于哪一个位置,哪一个位置的Fragment里的页面就要请求数据,所以,我们在MainActivity中,实现onPageChangeListener()监听器,监听其中的页面选择,在其中的onPageSelector()方法中去调用onLoad()

这就是整个关于加载页面的处理流程,我们可以看到,在这段逻辑中,大量的使用了封装,知识面向对象得核心思想,封装大大简化了我们的代码量,但是同时也使代码的复杂度大大上升了,必须环环相扣,才能做到滴水不漏,使应用运行成功。此处再附上两张逻辑处理图帮助自己理解。

ps:终于敲完了,已经凌晨4点。。。不说了,睡觉,明天继续!!!

谷歌电子市场开发流程(3)-关于加载界面的处理相关推荐

  1. 【SemiDrive源码分析】【X9芯片启动流程】27 - AP1 Android Preloader启动流程分析(加载atf、tos、bootloader镜像后进入BL31环境)

    [SemiDrive源码分析][X9芯片启动流程]27 - AP1 Android Preloader启动流程分析(加载atf.tos.bootloader镜像后进入BL31环境) 一.Android ...

  2. android 动画间隔时间,Android使用View Animation实现动画加载界面

    之前分别介绍了View Animation和Drawable Animation,学了就要用啊,今天给大家一个使用View Animation实现动画加载界面的实现. 首先先看一下实现效果. 下面是实 ...

  3. 电脑开机进不了系统卡在加载界面怎么办?

    电脑开机进不了系统卡在加载界面怎么办?有用户电脑弹出需要进行系统更新,不小心点到了系统更新的选项.因为自己不想进行系统更新,所以马上将电脑关机了.但是关机之后却发现系统一直卡在开机的界面中,无法进入桌 ...

  4. ps正在初始化html表面然后进不去,如何解决维护PE卡在加载界面无法继续

    用户在想用U盘装系统或者分区 引导修复都会进入到PE环节,PE是我们用户和装机员最喜欢的一种装系统,只要电脑硬件没问题,就可以随时随地装系统.使用过程中有时候会出现进入PE卡顿在加载界面,面这样的情况 ...

  5. safari 调试 打印刚加载界面时缓存的log信息 iOS Safari调试iPhone设备上的网页

    文章目录 1.开启电脑端safari的调试 2.开启手机端iphone的safari调试 3.打印刚加载界面时的log信息:进入到要调试的网页后点击刷新(reload)就可以了 4.参考博客 1.开启 ...

  6. Unity3d跨场景背景音乐和场景切换加载界面的设置!

    Unity3d以场景为单位,UI场景之间的背景音乐要一直播放,而场景切换之间的loading界面,需要在前一个场景执行某个按键进行击发,并在下个场景开始的时候消失. 虽然二者同时公共的需求,但具体还是 ...

  7. 解决研华数据采集板卡驱动包Xnavi在Win7系统下加载界面卡死问题

    问题:Xnavi驱动包在Win7系统下运行,无法进入驱动安装界面,一直停滞在加载界面. 处理过程与结果: 系统缺少一些补丁,需要更新系统或者安装以下补丁(Windows6.1-KB2921916)(W ...

  8. Macbook Pro黑屏和装双系统后开机一直卡在加载界面解决方案

    1 黑屏解决方法 下班的时候电脑没关机,直接盖上盖子,放在背包里回家.到家后打开电脑,发现屏幕无法启动,但是usb接上手机后,发现手机在充电. 证明电脑是在工作的,只是屏幕显示出现了问题.左shift ...

  9. 【Unity使用UGUI实现王者荣耀UI界面(三)】登录界面以及加载界面优化

    [Unity使用UGUI实现王者荣耀UI界面(三)]登录界面以及加载界面优化 [只是用来玩玩的,不要太当真] 效果显示: zhans 1. 加载界面进度100%跳转登录界面 这个功能好做,只需要将上次 ...

  10. WinForm使用多线程异步加载界面数据

    WinForm使用多线程异步加载界面数据 处于学习阶段,做个记录,如有写错,请多多指教. private void FrmQC111_Load(object sender, EventArgs e) ...

最新文章

  1. 如何在 Knative 中部署 WebSocket 和 gRPC 服务?
  2. 实习推荐 | 腾讯AI Lab虚拟人中心招聘算法工程师实习生
  3. 时间序列与R语言应用(part5)--移动平均MA模型及其可逆性
  4. ABAP Authorization object where used list in tcode SUIM
  5. 2016php技术面试题,一个php的面试题,大家看看
  6. c语言与python通信_python和c++通信示例
  7. angular之两种路由
  8. HTML5的表单验证属性--pattern
  9. 第一章 WebGL简介 Introduction
  10. samba (centos6.5)服务
  11. MSDN 访谈录(MSDN Show)C#编程
  12. 求解动力学模型的平衡点【matlab工具集_01】
  13. IDEA轻松实现.class文件反编译(超实用)
  14. mvvm框架 android,Android MVVM 框架 MVVMFramework
  15. 付费版百度指数 就是这么坑爹
  16. 【解决U盘无法访问】
  17. 2018 ACM-ICPC, Syrian Collegiate Programming Contest F. Pretests(子集dp)
  18. Flink入门系列05-时间语义
  19. 思科关闭日志_关于思科交换机的日志配置总结
  20. android cpu负载 工具,【专家专栏】Android性能测试之CPU

热门文章

  1. php读取excel最佳方案,用PHP读取excel(转)
  2. 车联网登录显示连接不上服务器,车联网,如何解决连接的问题?
  3. 解决idea下tomcat乱码
  4. excel表格坐标导入cad怎样操作?
  5. vsftpd配置系统用户为登陆用户
  6. Couldn‘t find ffmpeg or avconv - defaulting to ffmpeg, but may not work
  7. 11(1)-AirSim+四旋翼仿真-人工势场法动态避障
  8. 2021年皓丽新品- 86KD1 86寸纳米智慧黑板(电容屏)-产品说明
  9. 韩国瑜会见陆委会主委陈明通:别给高雄念紧箍咒
  10. Opencv学习笔记 超像素分割