LoadingPager抽取
学习笔记
如有错误之处请大家帮忙指出纠正__谢谢
-------------------------------------------------------------------------------------------------------------------------------------------
MainActivity中:
1 界面控件 : 顶部 指针 [ 引入指针控件 ], 底部ViewPager
现在设置FragmentPagerAdapter为ViewPager的数据适配器, viewPager中添加的View对象是由getItem( )方法中返回的Fragment中
onCreatView 方法里面的view对象
2 viewPager数据适配器继承自FragmentPagerAdapter
getItem(int position) 返回指针绑定的Fragment对象,我们需要onCreatView方法中返回的view
使用FragmentFactory 生产工厂,根据id生产对应的Fragment对象 (内存中有当前对象,复用之前的Fragment对象,内存中没有才创建)
FragmentFactory 生产工厂 : -->将对象存储到Map集合中 , 在创建对象之前,先从集合中取对象,如果没有才创建
getCount( ) 模块总个数
getPageTitle(int position)给应用设置标题
3 给指针设置数据适配器的时候,每一个fragment界面都有界面展示效果,所以将其进行抽取(BaseFragment),BaseFragment中去管理每一个
Fragment 的展示逻辑
在基类中管理每一个子界面的展示逻辑
4 viewPager设置完数据 适配器后, 将指针绑定到viewPager上 : pagertab_main.setViewPager(viewpager_main);//绑定指示器
5 创建基类BaseActivity继承自ActionBar 以后每个子类都继承自BaseActivity
应用中所有的activity界面都需要用到actionbar去管理头(Title),所以让所有activity父类继承至包含了ActionBar的Activity
获取FragmentManager管理者对象
如果对应的activity继承至ActionBarActivity,就一定要去再activity中配置Theme.AppCompat
android:theme="@style/Theme.AppCompat.Light"> 去除黑色的显示背景
6 顶部指针关联底部界面搞定
----------------------------------------------------------------------
7 ,每一个Fragment中都会有以下的四种展示情况,将以下的四套逻辑抽取到BaseFragment中去做管理
(1)成功展示数据的界面效果
(2)获取数据为空
(3)请求网络失败
(4)正在加载
(1),成功展示数据的界面效果 因为每一个Fragment中对应的成功的界面展示效果都不一致,所以对应View对象LoadingPage不能通过xml写死
(2),获取数据为空 ,每一个Fragment中,没有数据时候的展示效果都一致,数据为空的xml可以写死,构建一个数据为空xml布局结构 layout_empty
(3),请求网络失败 ,每一个Fragment中,获取不到数据时候的展示效果都一致,获取数据错误的xml可以写死,构建一个数据错误xml布局结构
layout_error
(4),正在加载,每一个Fragment中,加载数据时候的展示效果都一致,请求网络过程可以将其xml写死,构建一个正在加载xml布局结构 layout_loading
8 如果将这四套逻辑都写到BaseFragment中这个类的体系就显得太臃肿了 , 因此我们将其封装到单独的一个类LoadingPager中去做管理
9 LoadingPager继承自ViewGroup子类 , 因为需要往LoadingPager添加xml布局转化的view对象, 在这里我们就直接继承FrameLayout帧布局了 --> 这个类就等同于自定义控件了 , 就是自定义控件 , 复习三个构造
-------------------------------------------------
-------------
10 LoadingPager类 :
[1] 每种展示状态对应的其实就是一种View对象
(1)成功展示数据的界面效果
(2)获取数据为空
(3)请求网络失败
(4)正在加载
根据状态去决定,LoadingPage中展示那个界面
1,未加载
2,正在加载
3,加载为空
4,加载失败
5,加载成功
通过变量维护当前状态
-
1 //根据状态去决定,LoadingPage中展示那个界面 2 privateint STATE_UNLOAD =0; 3 privateint STATE_LOADING =1; 4 privateint STATE_LOAD_EMPTY =2; 5 privateint STATE_LOAD_ERROR =3; 6 privateint STATE_LOAD_SUCCESSED =4; 7 //通过一个变量维护当前状态 8 privateint current_state = STATE_UNLOAD; 9 //创建以上4个展示效果的view对象 10 privateView successedView; 11 privateView emptyView; 12 privateView errorView; 13 privateView loadingView;
[2] 构造中调用initLoadingPage()方法
添加三个已经确定的布局
根据当前状态决定,那个界面显示,那个隐藏 showSafePage();
[3] showSafePage(){ 作用: 切换到主线程 展示布局 showPage(); };
[4] showPager( ) 根据当前状态展示界面布局
1 if(loadingView!=null){ 2 loadingView.setVisibility((current_state == STATE_LOADING || current_state == STATE_UNLOAD)? 3 View.VISIBLE:View.GONE); 4 }
现在处理请求成功界面: 也是在showPager( )中 ,成功展示的界面需要定义成抽象方法,让自类去实现
在BaseFragment中实现此抽象方法
public abstract View onCreateViewSuccessed() ;
1 //如果成功展示界面的view对象为空 2 if(successedView == null && current_state == STATE_LOAD_SUCCESSED){ 3 //LoadingPage中不需要去管onCreateViewSuccessed具体实现,要做的就是讲这个成功展示的界面添加到LoadingPage中,然后展示 4 successedView = onCreateViewSuccessed(); 5 if(successedView!=null){ 6 addView(successedView,layoutParams); 7 } 8 } 9 10 if(successedView!=null){ 11 successedView.setVisibility(current_state == STATE_LOAD_SUCCESSED?View.VISIBLE:View.GONE); 12 }
BaseFragment也不知道成功界面显示什么样的,因此继续定义抽象方法,让所有的子类实现展示成功的抽象方法
LoadingPager抽取过程 [ onCreatViewSuccessed抽取 ]
![](https://images2015.cnblogs.com/blog/861354/201512/861354-20151220233956320-1948643631.png)
11 获取网络请求结果决定页面显示状态
我们到底显示那个界面需要根据 子类 请求网络的结果( 请求成功 ; 请求失败 ; 请求为空 )而显示对应的界面
将请求网络操作的的结果在LoadingPager中获取
定义show方法中 开启子线程
网络请求的状态已经封装在onLoad对象中 [ 该方法又是抽象,子类实现 ]final ResultState onLoad = onLoad(); //子类实现该方法,只有返回结果了,切换到主线程,将当前状态重新赋值为返回来的结果(现在当前状态已经发生变化,)调用根据当前状态刷新界面的方法 , 显示界面
使用枚举指定要返回的结果类型
1 public enum ResultState{ 2 STATE_EMPTY(2), 3 STATE_ERROR(3), 4 STATE_SUCCESSED(4); 5 6 private int state; 7 private ResultState(int state){ 8 this.state = state; 9 } 10 11 public int getState() { 12 return state; 13 } 14 }
每一个Fragment在请求网络过程中调用的方法,需要放置到子线程中
public abstract ResultState onLoad() ; --> 子类实现
onLoad抽取过程
-----------------------------------------------------
12 子类分别实现这两个抽象方法
子类中,只有 onLoad() 返回值为枚举的success后 ,子类中的onCreateViewSuccessed()方法才会执行
---------------------------------------------------------------------------------------------------------------
LoadingPager代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 根据当前状态来显示不同页面的自定义控件 3 * 4 * - 未加载 - 加载中 - 加载失败 - 数据为空 - 加载成功 5 * 6 * @author Kevin 7 * @date 2015-10-27 8 */ 9 public abstract class LoadingPage extends FrameLayout { 10 11 private static final int STATE_LOAD_UNDO = 1;// 未加载 12 private static final int STATE_LOAD_LOADING = 2;// 正在加载 13 private static final int STATE_LOAD_ERROR = 3;// 加载失败 14 private static final int STATE_LOAD_EMPTY = 4;// 数据为空 15 private static final int STATE_LOAD_SUCCESS = 5;// 加载成功 16 17 private int mCurrentState = STATE_LOAD_UNDO;// 当前状态 18 19 private View mLoadingPage; 20 private View mErrorPage; 21 private View mEmptyPage; 22 private View mSuccessPage; 23 24 public LoadingPage(Context context, AttributeSet attrs, int defStyle) { 25 super(context, attrs, defStyle); 26 initView(); 27 } 28 29 public LoadingPage(Context context, AttributeSet attrs) { 30 super(context, attrs); 31 initView(); 32 } 33 34 public LoadingPage(Context context) { 35 super(context); 36 initView(); 37 } 38 39 private void initView() { 40 // 初始化加载中的布局 41 if (mLoadingPage == null) { 42 mLoadingPage = UIUtils.inflate(R.layout.page_loading); 43 addView(mLoadingPage);// 将加载中的布局添加给当前的帧布局 44 } 45 46 // 初始化加载失败布局 47 if (mErrorPage == null) { 48 mErrorPage = UIUtils.inflate(R.layout.page_error); 49 addView(mErrorPage); 50 } 51 52 // 初始化数据为空布局 53 if (mEmptyPage == null) { 54 mEmptyPage = UIUtils.inflate(R.layout.page_empty); 55 addView(mEmptyPage); 56 } 57 58 showRightPage(); 59 } 60 61 // 根据当前状态,决定显示哪个布局 62 private void showRightPage() { 63 // if (mCurrentState == STATE_LOAD_UNDO 64 // || mCurrentState == STATE_LOAD_LOADING) { 65 // mLoadingPage.setVisibility(View.VISIBLE); 66 // } else { 67 // mLoadingPage.setVisibility(View.GONE); 68 // } 69 mLoadingPage 70 .setVisibility((mCurrentState == STATE_LOAD_UNDO || mCurrentState == STATE_LOAD_LOADING) ? View.VISIBLE 71 : View.GONE); 72 73 mErrorPage 74 .setVisibility(mCurrentState == STATE_LOAD_ERROR ? View.VISIBLE 75 : View.GONE); 76 77 mEmptyPage 78 .setVisibility(mCurrentState == STATE_LOAD_EMPTY ? View.VISIBLE 79 : View.GONE); 80 81 // 当成功布局为空,并且当前状态为成功,才初始化成功的布局 82 if (mSuccessPage == null && mCurrentState == STATE_LOAD_SUCCESS) { 83 mSuccessPage = onCreateSuccessView(); 84 if (mSuccessPage != null) { 85 addView(mSuccessPage); 86 } 87 } 88 89 if (mSuccessPage != null) { 90 mSuccessPage 91 .setVisibility(mCurrentState == STATE_LOAD_SUCCESS ? View.VISIBLE 92 : View.GONE); 93 } 94 } 95 96 // 开始加载数据 97 public void loadData() { 98 if (mCurrentState != STATE_LOAD_LOADING) {// 如果当前没有加载, 就开始加载数据 99 100 mCurrentState = STATE_LOAD_LOADING; 101 102 new Thread() { 103 @Override 104 public void run() { 105 final ResultState resultState = onLoad(); 106 107 // 运行在主线程 108 UIUtils.runOnUIThread(new Runnable() { 109 110 @Override 111 public void run() { 112 if (resultState != null) { 113 mCurrentState = resultState.getState();// 网络加载结束后,更新网络状态 114 // 根据最新的状态来刷新页面 115 showRightPage(); 116 } 117 } 118 }); 119 } 120 }.start(); 121 } 122 } 123 124 // 加载成功后显示的布局, 必须由调用者来实现 125 public abstract View onCreateSuccessView(); 126 127 // 加载网络数据, 返回值表示请求网络结束后的状态 128 public abstract ResultState onLoad(); 129 130 public enum ResultState { 131 STATE_SUCCESS(STATE_LOAD_SUCCESS), STATE_EMPTY(STATE_LOAD_EMPTY), STATE_ERROR( 132 STATE_LOAD_ERROR); 133 134 private int state; 135 136 private ResultState(int state) { 137 this.state = state; 138 } 139 140 public int getState() { 141 return state; 142 } 143 } 144 145 public static class Person { 146 147 public static Person P1 = new Person(10); 148 public static Person P2 = new Person(12); 149 public static Person P3 = new Person(19); 150 151 public Person(int age) { 152 153 } 154 } 155 156 // public enum Person { 157 // P1,P2,P3; 158 // } 159 160 }
BaseFragment
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public abstract class BaseFragment extends Fragment { 2 3 private LoadingPage mLoadingPage; 4 5 @Override 6 public View onCreateView(LayoutInflater inflater, ViewGroup container, 7 Bundle savedInstanceState) { 8 // 使用textview显示当前类的类名 9 // TextView view = new TextView(UIUtils.getContext()); 10 // view.setText(getClass().getSimpleName()); 11 mLoadingPage = new LoadingPage(UIUtils.getContext()) { 12 13 @Override 14 public View onCreateSuccessView() { 15 // 注意:此处一定要调用BaseFragment的onCreateSuccessView, 否则栈溢出 16 return BaseFragment.this.onCreateSuccessView(); 17 } 18 19 @Override 20 public ResultState onLoad() { 21 return BaseFragment.this.onLoad(); 22 } 23 24 }; 25 26 return mLoadingPage; 27 } 28 29 // 加载成功的布局, 必须由子类来实现 30 public abstract View onCreateSuccessView(); 31 32 // 加载网络数据, 必须由子类来实现 33 public abstract ResultState onLoad(); 34 35 // 开始加载数据 36 public void loadData() { 37 if (mLoadingPage != null) { 38 mLoadingPage.loadData(); 39 } 40 } 41 }
子类Fragment_用于展示当前页面
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class AppFragment extends BaseFragment { 2 3 //只有成功才走此方法 4 @Override 5 public View onCreateSuccessView() { 6 return null; 7 } 8 9 @Override 10 public ResultState onLoad() { 11 return ResultState.STATE_ERROR; 12 } 13 14 }