我们在网络请求数据的时候,通常有四种情况:
1、正在加载
2、加载失败
3、加载成功,但是没有数据
4、加载成功,同时返回数据
这时候需要我们根据这四种情况显示不同的页面视图。
这里我们可以自定义一个LoadingPage类来实现这四种情况的切换。
一、新建一个LoadingPage类继承FrameLayout
1.定义4种不同的显示状态
state_loading=1;
state_error=2;
state_empty=3;
state_success=4;
state_current=1;
2.提供4种不同界面:
正在加载中
加载失败
加载成功,但是数据为空
加载成功,且有数据
3.根据state_current的值,决定显示哪个界面。(初始化时,应该显示:正在加载)
4.在类中,实现联网操作,根据联网的结果,修改state_current的值,决定显示哪个界面。
5.如果是state_current=4,需要考虑如何将数据传递给具体的Fragment.
LoadingPage.class
import android.content.Context;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import com.willkong.p2pclient.R;
import com.willkong.p2pclient.util.UIUtils;
/**
* 作者: willkong on 2017/11/8.
* 作用:加载页四种情况:1、正在加载 2、加载失败 3、加载成功,但是没有数据 4、加载成功,同时返回数据
*/
public abstract class LoadingPage extends FrameLayout{
//1.定义4种不同的显示状态
private static final int STATE_LOADING=1;
private static final int STATE_ERROR=2;
private static final int STATE_EMPTY=3;
private static final int STATE_SUCCESS=4;
private static int state_current=STATE_LOADING;//默认情况下,当前状态为正在加载
//2.提供4种不同的界面
private View view_loading;
private View view_error;
private View view_empty;
private View view_success;
private LayoutParams params;
public LoadingPage(@NonNull Context context) {
this(context,null);
}
public LoadingPage(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public LoadingPage(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//初始化方法
private void init() {
//实例化view
//1、提供布局显示的参数
params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
if (view_loading==null){
//2、加载布局
view_loading = UIUtils.getView(R.layout.page_loading);
//3、添加到当前的Fragment中
addView(view_loading, params);
}
if (view_empty==null){
//2、加载布局
view_empty = UIUtils.getView(R.layout.page_empty);
//3、添加到当前的Fragment中
addView(view_empty, params);
}
if (view_error==null){
//2、加载布局
view_error = UIUtils.getView(R.layout.page_error);
//3、添加到当前的Fragment中
addView(view_error, params);
}
//3、根据state_current的值,决定显示哪个界面。(初始化时,应该显示:正在加载)
showSafePage();
}
//保证如下的操作在主线程中执行的,更新界面
private void showSafePage() {
UIUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
//保证runnable中的操作在主线程中执行
showPage();
}
});
}
//更新界面
private void showPage() {
//根据state_current的值,决定显示哪个view
view_loading.setVisibility(state_current==STATE_LOADING?VISIBLE:INVISIBLE);
view_error.setVisibility(state_current==STATE_ERROR?VISIBLE:INVISIBLE);
view_empty.setVisibility(state_current==STATE_EMPTY?VISIBLE:INVISIBLE);
if (view_success==null){
view_success = UIUtils.getView(layoutId());
addView(view_success,params);
}
view_success.setVisibility(state_current==STATE_SUCCESS?VISIBLE:INVISIBLE);
}
public abstract int layoutId();
private ResultState resultState;
//在show()方法中实现联网加载数据
public void show(){
String url = url();
//不需要联网
if (TextUtils.isEmpty(url)){
resultState = ResultState.SUCCESS;
resultState.setContent("");
loadImage();
return;
}
//4.在类中,实现联网操作,根据联网的结果,修改state_current的值,决定显示哪个界面。
AsyncHttpClient client = new AsyncHttpClient();
client.get(url(),params(),new AsyncHttpResponseHandler(){
@Override
public void onSuccess(String content) {
if (TextUtils.isEmpty(content)){
resultState = ResultState.EMPTY;
resultState.setContent("");
}else {
resultState = ResultState.SUCCESS;
resultState.setContent(content);
}
loadImage();
}
@Override
public void onFailure(Throwable error, String content) {
resultState = ResultState.ERROR;
resultState.setContent("");
loadImage();
}
});
}
private void loadImage() {
switch (resultState){
case ERROR:
state_current = STATE_ERROR;
break;
case EMPTY:
state_current = STATE_EMPTY;
break;
case SUCCESS:
state_current = STATE_SUCCESS;
break;
}
//根据修改以后的state_current,更新视图的显示。
showSafePage();
//5.如果是state_current=4,需要考虑如何将数据传递给具体的Fragment.如果联网成功了,把内容回调给界面
if (state_current==STATE_SUCCESS){
onSuccess(resultState,view_success);
}
}
protected abstract void onSuccess(ResultState resultState, View view_success);
//提供联网的请求地址
protected abstract String url();
//提供联网的请求参数
protected abstract RequestParams params();
//提供枚举类,封装联网后的状态值和数据
public enum ResultState{
ERROR(2),EMPTY(3),SUCCESS(4);
int state;
ResultState(int state){
this.state = state;
}
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
}
BaseFragment.class
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.loopj.android.http.RequestParams;
import com.willkong.p2pclient.ui.LoadingPage;
import butterknife.ButterKnife;
/**
* 作者: willkong on 2017/11/3.
* 作用:HomeFragment、InvestFragment、MeFragment、MoreFragment的基类
*/
public abstract class BaseFragment extends Fragment {
private LoadingPage loadingPage;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
loadingPage = new LoadingPage(container.getContext()){
@Override
public int layoutId() {
return getLayoutId();
}
@Override
protected void onSuccess(ResultState resultState, View view_success) {
ButterKnife.bind(BaseFragment.this, view_success);
initTitle();
initData(resultState.getContent());
}
@Override
protected String url() {
return getUrl();
}
@Override
protected RequestParams params() {
return getParams();
}
};
return loadingPage;
}
//为了保证loadingPage不为null
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
show();
}
protected abstract RequestParams getParams();
protected abstract String getUrl();
//初始化界面的数据
protected abstract void initData(String content);
//初始化title
protected abstract void initTitle();
//提供一个创建方法,提供布局
public abstract int getLayoutId();
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
//联网请求数据
public void show(){
loadingPage.show();
}
}
MyApplication.class
import android.app.Application;
import android.content.Context;
import android.os.Handler;
/**
* 作者: willkong on 2017/10/31.
* 作用:APP全局
*/
public class MyApplication extends Application{
//在整个应用执行过程中,需要提供的变量
public static Context context;//需要使用的上下文对象:application实例
public static Handler handler;//需要使用的handler
public static Thread mainThread;//提供主线程对象
public static int mainThreadId;//提供主线程对象的id
@Override
public void onCreate() {
super.onCreate();
context = this.getApplicationContext();
handler = new Handler();
mainThread = Thread.currentThread();//实例化当前Application的线程即为主线程
mainThreadId = android.os.Process.myTid();//获取当前线程的id
//设置未捕获异常的处理器
// CrashHandler.getInstance().init();
}
}
UIUtils.class
import android.content.Context;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.Toast;
import com.willkong.p2pclient.common.MyApplication;
/**
* 作者: willkong on 2017/10/31.
* 作用:专门提供为处理一些UI相关的问题而创建的工具类,
* 提供资源获取的通用方法,避免每次都写重复的代码获取结果。
*/
public class UIUtils {
public static Context getContext(){
return MyApplication.context;
}
public static Handler getHandler(){
return MyApplication.handler;
}
//返回指定colorId对应的颜色值
public static int getColor(int colorId){
return ContextCompat.getColor(getContext(),colorId);
}
//加载指定viewId的视图对象,并返回
public static View getView(int viewId){
View view = View.inflate(getContext(), viewId, null);
return view;
}
public static String[] getStringArr(int strArrId){
String[] stringArray = getContext().getResources().getStringArray(strArrId);
return stringArray;
}
//将dp转化为px
public static int dp2px(int dp){
//获取手机密度
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5);//实现四舍五入
}
public static int px2dp(int px){
//获取手机密度
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (px / density + 0.5);//实现四舍五入
}
//保证runnable中的操作在主线程中执行
public static void runOnUiThread(Runnable runnable) {
if(isInMainThread()){
runnable.run();
}else{
UIUtils.getHandler().post(runnable);
}
}
//判断当前线程是否是主线程
private static boolean isInMainThread() {
int currentThreadId = android.os.Process.myTid();
return MyApplication.mainThreadId == currentThreadId;
}
public static void toast(String message,boolean isLengthLong){
Toast.makeText(UIUtils.getContext(), message,isLengthLong? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();
}
}
Fragment中的调用如:HomeFragment.class
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.loopj.android.http.RequestParams;
import com.squareup.picasso.Picasso;
import com.willkong.p2pclient.R;
import com.willkong.p2pclient.bean.Image;
import com.willkong.p2pclient.bean.Index;
import com.willkong.p2pclient.bean.Product;
import com.willkong.p2pclient.common.BaseFragment;
import com.willkong.p2pclient.ui.RoundProgress;
import com.youth.banner.Banner;
import com.youth.banner.BannerConfig;
import com.youth.banner.Transformer;
import com.youth.banner.loader.ImageLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import butterknife.Bind;
/**
* 作者: willkong on 2017/10/25.
* 作用:首页
*/
public class HomeFragment extends BaseFragment {
@Bind(R.id.iv_title_back)
ImageView ivTitleBack;
@Bind(R.id.tv_title)
TextView tvTitle;
@Bind(R.id.iv_title_setting)
ImageView ivTitleSetting;
@Bind(R.id.banner)
Banner banner;
@Bind(R.id.tv_home_product)
TextView tvHomeProduct;
@Bind(R.id.tv_home_yearrate)
TextView tvHomeYearrate;
@Bind(R.id.roundPro_home)
RoundProgress roundProHome;
@Override
protected RequestParams getParams() {
return null;
}
@Override
protected String getUrl() {
// return AppNetConfig.INDEX;
return null;
}
private Index index;
private int currentProgress;
@Override
protected void initData(String content) {
index = new Index();
if (!TextUtils.isEmpty(content)){
//解析json数据
JSONObject jsonObject = JSON.parseObject(content);
//解析json对象数据
String proInfo = jsonObject.getString("proInfo");
Product product = JSON.parseObject(proInfo,Product.class);
//解析json数组数据
String imageArr = jsonObject.getString("imageArr");
List images = jsonObject.parseArray(imageArr, Image.class);
index.product = product;
index.images = images;
//更新页面数据
tvHomeProduct.setText(product.name);
tvHomeYearrate.setText(product.yearRate + "%");
//获取数据中的进度
currentProgress = Integer.parseInt(index.product.progress);
//在分线程中实现进度的动态变化
// new Thread(runnable).start();
roundProHome.runWithAnimation(100, currentProgress, 50);
//设置banner样式
banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE);
//设置图片加载器
banner.setImageLoader(new GlideImageLoader());
//设置图片地址的构成集合
ArrayList imgesUrl = new ArrayList(index.images.size());
for (int i = 0; i < index.images.size(); i++) {
imgesUrl.add(index.images.get(i).IMAURL);
}
banner.setImages(imgesUrl);
//设置banner动画效果
banner.setBannerAnimation(Transformer.DepthPage);
//设置标题集合(当banner样式有显示title时)
String[] titles = new String[]{"分享砍学费", "人脉总动员", "想不到你是这样的app"};
banner.setBannerTitles(Arrays.asList(titles));
//设置自动轮播,默认为true
banner.isAutoPlay(true);
//设置轮播时间
banner.setDelayTime(1500);
//设置指示器位置(当banner模式中有指示器时)
banner.setIndicatorGravity(BannerConfig.CENTER);
//banner设置方法全部调用完毕时最后调用
banner.start();
}
}
@Override
protected void initTitle() {
ivTitleBack.setVisibility(View.GONE);
tvTitle.setText("首页");
ivTitleSetting.setVisibility(View.GONE);
}
@Override
public int getLayoutId() {
return R.layout.fragment_home;
}
class GlideImageLoader extends ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
/**
注意:
1.图片加载器由自己选择,这里不限制,只是提供几种使用方法
2.返回的图片路径为Object类型,由于不能确定你到底使用的那种图片加载器,传输的到的是什么格式,那么这种就使用Object接收和返回,你只需要强转成你传输的类型就行,切记不要胡乱强转!
*/
//Picasso 加载图片简单用法
Picasso.with(context).load((String) path).into(imageView);
}
}
}