欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android使用DataBinding来设置空状态

程序员文章站 2023-11-17 12:34:16
写在前面 在平时的开发之中,我们需要对于数据加载的情况进行展示: 空数据 网络异常 加载中等等情况 现在设置页面状态的方式有多种,由于笔者近期...

写在前面

在平时的开发之中,我们需要对于数据加载的情况进行展示:

  1. 空数据
  2. 网络异常
  3. 加载中等等情况

现在设置页面状态的方式有多种,由于笔者近期一直在使用databinding,而数据绑定通过改变模型来展示view的方式和状态页的设置也满契合的。

所以这里就讲讲使用databinding来设置android中的各种状态页。很简单,先看看效果

android使用DataBinding来设置空状态

首先

在app的build.gradle文件中开启databinding

android{
  ...
  databinding {
    enabled = true
  }
}

我们先定义一些用于状态的注解emptystate

/**
 * 页面描述:空状态
 * <p>
 * created by ditclear on 2017/2/24.
 */
@intdef({normal, progress, empty, net_error, not_available})
@retention(retentionpolicy.source)
public @interface emptystate {

  int normal = -1; //正常
  int progress = -2;//显示进度条

  int empty = 11111; //列表数据为空
  int net_error = 22222; //网络未连接
  int not_available = 33333; //服务器不可用

  //...各种页面的空状态,可以自己定义、添加

}

再自定义一个异常emptyexception用于显示我们需要的状态信息

/**
 * 页面描述:异常
 * <p>
 * created by ditclear on 2017/3/5.
 */
public class emptyexception extends exception {

  private int code;

  public emptyexception(@emptystate int code) {
    super();
    this.code = code;
  }


  @emptystate
  public int getcode() {
    return code;
  }

  public void setcode(@emptystate int code) {
    this.code = code;
  }
}

现在,大多数展示状态页的控件都会提供

  1. 加载中的进度条
  2. 错误信息
  3. 空状态
  4. ...

所以我们的目标也是显示这些

布局

以数据绑定的形式进行布局,使用statemodel来控制状态页展示的消息

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
  >

  <data>

    <import type="android.view.view"/>

    <variable
      name="statemodel"
      type="com.ditclear.app.state.statemodel"/>
  </data>

  <relativelayout
    android:id="@+id/rv_empty_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background"
    android:clickable="true"
    android:focusableintouchmode="true"
    android:visibility="@{statemodel.empty?view.visible:view.gone}">

    <android.support.v4.widget.contentloadingprogressbar
      style="?android:attr/progressbarstyle"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerinparent="true"
      android:visibility="@{statemodel.progress?view.visible:view.gone}"/>

    <linearlayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_alignparentbottom="true"
      android:layout_alignparentleft="true"
      android:layout_alignparentstart="true"
      android:gravity="center"
      android:orientation="vertical"
      android:visibility="@{statemodel.progress?view.invisible:view.visible}">

      <imageview
        android:id="@+id/none_data"
        android:layout_width="345dp"
        android:layout_height="180dp"
        android:scaletype="fitcenter"
        android:src="@{statemodel.emptyiconres}"/>


      <textview
        android:layout_width="wrap_content"
        android:layout_height="25dp"
        android:layout_below="@+id/none_data"
        android:layout_centerhorizontal="true"
        android:text="@{statemodel.currentstatelabel}"
        android:textsize="16sp"/>


    </linearlayout>
  </relativelayout>
</layout>

布局文件中有几个方法

  1. empty 用于控制状态页是显示还是隐藏,数据加载正常(即状态为normal)的时候隐藏,否则展示
  2. isprogress 是否显示加载中,如果显示进度条(即状态为progress),就隐藏异常页
  3. emptyiconres 显示状态的图片信息
  4. currentstatelabel 显示状态的文字消息

我们定义状态的viewmodel ,就叫statemodel,来控制状态

/**
 * 页面描述:状态页面设置模型
 * <p>
 * created by ditclear on 2017/2/24.
 */

public class statemodel extends baseobservable {

  private context mcontext = myapp.instance();

  @emptystate
  private int emptystate = emptystate.normal;

  private boolean empty;

  public int getemptystate() {
    return emptystate;
  }

  /**
   * 设置状态
   *
   * @param emptystate
   */
  public void setemptystate(@emptystate int emptystate) {
    this.emptystate = emptystate;
    notifychange();
  }

  /**
   * 显示进度条
   *
   * @return
   */
  public boolean isprogress() {
    return this.emptystate == emptystate.progress;
  }

  /**
   * 根据异常显示状态
   *
   * @param e
   */
  public void bindthrowable(throwable e) {
    if (e instanceof emptyexception) {
      @emptystate
      int code = ((emptyexception) e).getcode();

      setemptystate(code);
    }
  }

  public boolean isempty() {
    return this.emptystate != emptystate.normal;
  }

  /**
   * 空状态信息
   *
   * @return
   */
  @bindable
  public string getcurrentstatelabel() {

    switch (emptystate) {
      case emptystate.empty:
        return mcontext.getstring(r.string.no_data);
      case emptystate.net_error:
        return mcontext.getstring(r.string.please_check_net_state);
      case emptystate.not_available:
        return mcontext.getstring(r.string.server_not_avaliabe);
      default:
        return mcontext.getstring(r.string.no_data);
    }
  }

  /**
   * 空状态图片
   *
   * @return
   */
  @bindable
  public drawable getemptyiconres() {
    switch (emptystate) {
      case emptystate.empty:
        return contextcompat.getdrawable(mcontext, r.drawable.ic_visibility_off_green_400_48dp);
      case emptystate.net_error:
        return contextcompat.getdrawable(mcontext, r.drawable.ic_signal_wifi_off_green_400_48dp);
      case emptystate.not_available:
        return contextcompat.getdrawable(mcontext, r.drawable.ic_cloud_off_green_400_48dp);
      default:
        return contextcompat.getdrawable(mcontext, r.drawable.ic_visibility_off_green_400_48dp);
    }
  }

}

很普通的视图模型,主要有几个用于判断状态显示的方法

  1. bindthrowable 根据异常显示状态
  2. setemptystate 方法用来设置当前的状态,通过notifychange来通知布局文件改变

下面讲讲实际运用:

在activity或者fragment布局中,添加状态页的布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

  <data>

    <import type="android.view.view"/>

    <variable
      name="statemodel"
      type="com.ditclear.app.state.statemodel"/>

  </data>

  <com.ditclear.app.scrollchildswiperefreshlayout
    android:id="@+id/refresh_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <relativelayout
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical">


      <android.support.v4.widget.nestedscrollview
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillviewport="false"
        android:overscrollmode="always"
        android:visibility="@{statemodel.empty?view.gone:view.visible}">

        <textview
          android:id="@+id/content_tv"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"/>


      </android.support.v4.widget.nestedscrollview>


      <include
        layout="@layout/widget_layout_empty"
        app:statemodel="@{statemodel}"/>

    </relativelayout>
  </com.ditclear.app.scrollchildswiperefreshlayout>
</layout>

最后在activity或者fragment中我们只需要通过state.bindthrowable()和state.setemptystate()方法便可以轻松设置各种各样的状态。

loaddata().subscribe(new subscriber<list<contributor>>() {

  @override
  public void onstart() {
    super.onstart();
    if (!mmainbinding.refreshlayout.isrefreshing()) {
      mstatemodel.setemptystate(emptystate.progress);
    }
  }

  @override
  public void oncompleted() {
    mstatemodel.setemptystate(emptystate.normal);

  }

  @override
  public void onerror(throwable e) {
    mmainbinding.refreshlayout.setrefreshing(false);
    mstatemodel.bindthrowable(e);
    toast.maketext(mainactivity.this, mstatemodel.getcurrentstatelabel(), toast.length_short).show();


  }

  @override
  public void onnext(list<contributor> contributors) {
    mmainbinding.refreshlayout.setrefreshing(false);
    if (contributors == null || contributors.isempty()) {
      onerror(new emptyexception(emptystate.empty));
    } else {
      mmainbinding.contenttv.settext(contributors.tostring());
    }
  }
});

写在最后

对于要使用数据来控制视图状态的,使用databinding实在是一个事半功倍的方式。而且也十分容易理解。

最后demo地址:statebinding_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。