前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)

一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)

作者头像
Petterp
发布2022-02-09 11:59:12
发布2022-02-09 11:59:12
1.2K00
代码可运行
举报
文章被收录于专栏:JetPackJetPack
运行总次数:0
代码可运行

在最近公布的比赛框架中,发现了页面加载管理类,觉得挺有用的,所以做个简单的笔记。

什么是页面加载管理类呢?(大佬可直接跳过翻看实现过程)

如果能有这个问题,那么很好,哈哈哈,你和我一样,刚开始都挺疑惑的。 我们一般在写网络请求的时候,如果不涉及什么MVP,或者别的,就一个简单网络请求,然后再成功的结果里刷新View,请求过程中总不能白屏吧,所以有些人可能会让转一个圈,或者显示加载中的布局,然后等成功后再隐藏掉,显示具体的布局view。这样的话,也没什么问题,但是如果你的状态需要多个,这个时候就很烦了。总不能每个状态的判断一下吧。再者说这样也不利于你解耦。

出于上面的需求,我们用下面的demo,来解决问题,先用一张图来看效果吧。

我们来具体看一下实现过程

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 页面加载管理类,根据不同的状态显示不同的view
 */
public abstract class ContentPage extends FrameLayout{

	/**加载中的view*/
	private View loadingView;
	/**加载失败的view*/
	private View errorView;
	/**加载数据为空的view*/
	private View emptyView;
	/**加载成功的view*/
	private View successView;
	/**默认是加载中的状态*/
	private PageState mState = PageState.STATE_LOADING;

	/**
	 * 定义页面状态常量
	 *
	 */
	public enum PageState{
		STATE_LOADING(0),/*加载中的状态*/
		STATE_SUCCESS(1),/*加载成功的状态*/
		STATE_ERROR(2),/*加载失败的状态*/
		STATE_EMPTY(3);/*加载数据为空的状态*/
		private int value;
		PageState(int value){
			this.value = value;
		}
		public int getValue(){
			return value;
		}
	}

	public ContentPage(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initPage();
	}
	public ContentPage(Context context, AttributeSet attrs) {
		super(context, attrs);
		initPage();
	}
	public ContentPage(Context context) {
		super(context);
		initPage();
	}

	/**
	 * 初始化Page
	 */
	private void initPage(){
		LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
		if(loadingView==null){/*天然往ContentPage中添加4个状态对应的view,然后根据不同状态,显示不同的view,添加LoadingView*/
			loadingView = View.inflate(getContext(), R.layout.page_loading, null);
		}
		addView(loadingView, params);
		if(errorView==null){/*添加ErrorView*/
			errorView = View.inflate(getContext(), R.layout.page_error, null);
			Button btn_reload = errorView.findViewById(R.id.btn_reload);
			btn_reload.setOnClickListener(v -> {
				mState = PageState.STATE_LOADING;
				showPage();
				loadDataAndRefreshPage();/*重新加载*/
			});
		}
		addView(errorView, params);
		if(emptyView==null){/*添加EmptyView*/
			emptyView = View.inflate(getContext(), R.layout.page_empty, null);
		}
		addView(emptyView, params);
		if(successView==null){/*添加SuccessView*/
			successView = createSuccessView();
		}
		if(successView==null){
			throw new IllegalArgumentException("The method createSuccessView() can not return null!");
		}else {
			addView(successView, params);
		}
		showPage();/*根据不同的state显示不同的view*/
		loadDataAndRefreshPage();/*请求数据然后刷新View*/
	}

	/**
	 * 请求服务器的数据,然后根据加载的数据刷新View
	 */
	private void loadDataAndRefreshPage(){
		new Thread(){
			public void run() {
				Object result = loadData();/*获取加载完成的数据*/
				mState = checkData(result);/*根据数据判断当前page的状态*/
				/*根据最新state,刷新View*/
				CommonUtil.runOnUIThread(() -> showPage());
			}
		}.start();
	}

	/**
	 * 根据数据检查对应的状态
	 * @return
	 */
	private PageState checkData(Object result){
		if(result!=null){
			if(result instanceof List){
				List list = (List) result;
				if(list.size()==0){
					return PageState.STATE_EMPTY;/*加载数据为空*/
				}else {
					return PageState.STATE_SUCCESS;/*加载成功*/
				}
			}else {
				return PageState.STATE_SUCCESS;/*加载成功*/
			}
		}else {
			return PageState.STATE_ERROR;/*加载失败*/
		}
	}

	public void refreshPage(Object o) {
		if (o == null) {
			//说明木有数据,那么对应的state应该是error
			mState = PageState.STATE_ERROR;
		} else {
			//说明请求回来的有数据,那么对应的state应该是success
			mState = PageState.STATE_SUCCESS;
		}
		showPage();
	}


	/**
	 * 根据不同的state显示不同的view
	 */
	private void showPage(){
		loadingView.setVisibility(mState== PageState.STATE_LOADING?View.VISIBLE:View.INVISIBLE);
		errorView.setVisibility(mState== PageState.STATE_ERROR?View.VISIBLE:View.INVISIBLE);
		emptyView.setVisibility(mState== PageState.STATE_EMPTY?View.VISIBLE:View.INVISIBLE);
		successView.setVisibility(mState== PageState.STATE_SUCCESS?View.VISIBLE:View.INVISIBLE);
	}

	/**
	 * 每个界面的成功view都不一样,应该由每个界面自己提供
	 * @return
	 */
	public abstract View createSuccessView();

	/**
	 * 由于每个界面加载数据的过程不一样,我只需要关心它加载回来之后的数据,然后根据数据刷新View
	 * @return
	 */
	public abstract Object loadData();
}

现在看一下它的四种不同状态view

加载中 Loading...

代码语言:javascript
代码运行次数:0
运行
复制
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        style="@android:style/Widget.ProgressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:indeterminateDrawable="@drawable/indeterminate_drawable" />

</FrameLayout>

加载失败

代码语言:javascript
代码运行次数:0
运行
复制
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center" >

        <ImageView
            android:id="@+id/page_iv"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_centerHorizontal="true"
            android:scaleType="centerInside"
            android:src="@drawable/ic_error_page" />

        <Button
            android:id="@+id/btn_reload"
            android:layout_width="wrap_content"
            android:layout_height="34dp"
            android:layout_below="@id/page_iv"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:background="@drawable/btn_bg"
            android:ellipsize="end"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:singleLine="true"
            android:text="加载失败,点击重试"
            android:textColor="#ff717171"
            android:textSize="16sp" />
    </RelativeLayout>

</FrameLayout>

数据为null

代码语言:javascript
代码运行次数:0
运行
复制
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/tree"
        android:contentDescription="@string/no_data" />


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="@string/no_data"
        app:layout_constraintTop_toBottomOf="@id/image"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

</android.support.constraint.ConstraintLayout>

加载成功

这个布局就不用写了,就是你自己要显示的布局

那么具体在代码中如何使用呢,我们看下面这个Demo。

先是一个BaseFragment的基类。

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * @author Petterp
 * @date 2019/5/21.
 */
public abstract class BaseFragment extends SupportFragment implements View.OnClickListener {
    public ContentPage contentPage;
    public ProgressDialog pdLoading;
    protected Activity mActivity;
    protected Context mContext;
    private Unbinder mUnBinder;

    @Override
    public void onAttach(Context context) {
        mActivity = (Activity) context;
        mContext = context;
        super.onAttach(context);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        /*
         * 初始化pdLoading
         */
        pdLoading = new ProgressDialog(getActivity());
        pdLoading.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pdLoading.setMessage("请稍后");
        pdLoading.setCanceledOnTouchOutside(false);
        pdLoading.setCancelable(true);

        if (contentPage == null) {
            contentPage = new ContentPage(getActivity()) {
                @Override
                public Object loadData() {
                    return requestData();
                }

                @Override
                public View createSuccessView() {
                    return getSuccessView();
                }
            };
        } else {
          removeSelfFromParent(contentPage);
        }
        return contentPage;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mUnBinder = ButterKnife.bind(this, view);
    }

    /**
     * 初始化 Toolbar
     */
    protected void initToolBar(Toolbar toolbar, boolean homeAsUpEnabled, String title) {
        ((BaseActivity) getActivity()).initToolBar(toolbar, homeAsUpEnabled, title);
    }
    /**
     * 刷新状态
     *
     */
    public void refreshPage(Object o) {
        contentPage.refreshPage(o);
    }

    /**
     * 返回据的fragment填充的具体View
     */
    protected abstract View getSuccessView();

    /**
     * 返回请求服务器的数据
     */
    protected abstract Object requestData();


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mUnBinder.unbind();
    }

    public void removeSelfFromParent(View child) {
		// 获取父view
		if (child != null) {
			ViewParent parent = child.getParent();
			if (parent instanceof ViewGroup) {
				ViewGroup viewGroup = (ViewGroup) parent;
				// 将自己移除
				viewGroup.removeView(child);
			}
		}
	}

}

然后是一个模拟Fragment

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 模拟Fragment
 */
public class FirstFragment extends BaseFragment {
    
    @Override
    protected View getSuccessView() {
        TextView textView = new TextView(getActivity());
        textView.setText("第一页");
        return textView;
    }

    @Override
    protected Object requestData() {
        SystemClock.sleep(1000);/*模拟请求服务器的延时过程*/
        return "";/*加载成功*/
    }

    @Override
    public void onClick(View view) {

    }

    /**
     * 类似于 Activity的 onNewIntent()
     */
    @Override
    public void onNewBundle(Bundle args) {
        super.onNewBundle(args);
    }
}

好啦,具体就是这样呢,相应的注释都挺详细的,如果有什么地方不对,也欢迎大家指出。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 现在看一下它的四种不同状态view
    • 加载中 Loading...
    • 加载失败
    • 数据为null
    • 加载成功
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档