optimize state layout,Resource, etc

androidx
Zhanty 5 years ago
parent bb3620ddf3
commit 5eba23a1e9
  1. 72
      lib_base/src/main/java/com/android/base/app/fragment/RefreshLoadMoreStateLayoutImpl.kt
  2. 12
      lib_base/src/main/java/com/android/base/app/fragment/RefreshableStateLayoutImpl.java
  3. 6
      lib_base/src/main/java/com/android/base/app/ui/StateLayoutConfig.java
  4. 7
      lib_base/src/main/java/com/android/base/app/ui/UIEx.kt
  5. 61
      lib_base/src/main/java/com/android/base/data/Resource.java
  6. 24
      lib_base/src/main/java/com/android/base/data/Resource.kt
  7. 16
      lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java
  8. 25
      lib_base/src/main/java/com/android/base/widget/StateActionProcessor.java
  9. 10
      lib_base/src/main/java/com/android/base/widget/StateProcessor.java

@ -2,10 +2,10 @@ package com.android.base.app.fragment
import android.graphics.drawable.Drawable
import android.view.View
import com.android.base.app.ui.CommonId
import com.android.base.app.ui.*
import com.android.base.widget.StateProcessor
internal class RefreshLoadMoreStateLayoutImpl private constructor(private val mLayout: View) : StateLayout, StateLayoutConfig {
internal class RefreshLoadMoreStateLayoutImpl private constructor(layout: View) : StateLayout, StateLayoutConfig {
companion object {
fun init(view: View): RefreshLoadMoreStateLayoutImpl {
@ -13,56 +13,72 @@ internal class RefreshLoadMoreStateLayoutImpl private constructor(private val mL
}
}
private var mMultiStateView: StateLayout = mLayout.findViewById<View>(CommonId.STATE_ID) as StateLayout
private var mRefreshView: RefreshLoadMoreView
private var _multiStateView: StateLayout? = layout.findViewById<View>(CommonId.STATE_ID) as? StateLayout
private var _refreshView: RefreshLoadMoreView
val refreshView: RefreshLoadMoreView
get() = mRefreshView
get() = _refreshView
init {
val refreshLayout = mLayout.findViewById<View>(CommonId.REFRESH_ID)
mRefreshView = RefreshLoadViewFactory.createRefreshView(refreshLayout)
val refreshLayout = layout.findViewById<View>(CommonId.REFRESH_ID)
?: throw NullPointerException("You need to provide a refreshable layout with id R.id.base_refresh_layout in your xml.")
_refreshView = RefreshLoadViewFactory.createRefreshView(refreshLayout)
}
override fun showLoadingLayout() = mMultiStateView.showLoadingLayout()
override fun showContentLayout() = mMultiStateView.showContentLayout()
override fun showEmptyLayout() = mMultiStateView.showEmptyLayout()
override fun showErrorLayout() = mMultiStateView.showErrorLayout()
override fun showRequesting() = mMultiStateView.showRequesting()
override fun showBlank() = mMultiStateView.showBlank()
override fun showNetErrorLayout() = mMultiStateView.showNetErrorLayout()
override fun showServerErrorLayout() = mMultiStateView.showServerErrorLayout()
override fun showLoadingLayout() = checkMultiStateView().showLoadingLayout()
override fun showContentLayout() = checkMultiStateView().showContentLayout()
override fun showEmptyLayout() = checkMultiStateView().showEmptyLayout()
override fun showErrorLayout() = checkMultiStateView().showErrorLayout()
override fun showRequesting() = checkMultiStateView().showRequesting()
override fun showBlank() = checkMultiStateView().showBlank()
override fun showNetErrorLayout() = checkMultiStateView().showNetErrorLayout()
override fun showServerErrorLayout() = checkMultiStateView().showServerErrorLayout()
override fun getStateLayoutConfig(): StateLayoutConfig = mMultiStateView.stateLayoutConfig
override fun getStateLayoutConfig(): StateLayoutConfig = checkMultiStateView().stateLayoutConfig
override fun setStateMessage(state: Int, message: CharSequence?): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.setStateMessage(state, message)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.setStateMessage(state, message)
return checkMultiStateView().stateLayoutConfig
}
override fun setStateIcon(state: Int, drawable: Drawable?): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.setStateIcon(state, drawable)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.setStateIcon(state, drawable)
return checkMultiStateView().stateLayoutConfig
}
override fun setStateIcon(state: Int, drawableId: Int): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.setStateIcon(state, drawableId)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.setStateIcon(state, drawableId)
return checkMultiStateView().stateLayoutConfig
}
override fun setStateAction(state: Int, actionText: CharSequence?): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.setStateAction(state, actionText)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.setStateAction(state, actionText)
return checkMultiStateView().stateLayoutConfig
}
override fun setStateRetryListener(retryActionListener: OnRetryActionListener?): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.setStateRetryListener(retryActionListener)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.setStateRetryListener(retryActionListener)
return checkMultiStateView().stateLayoutConfig
}
override fun disableOperationWhenRequesting(disable: Boolean): StateLayoutConfig {
mMultiStateView.stateLayoutConfig.disableOperationWhenRequesting(disable)
return mMultiStateView.stateLayoutConfig
checkMultiStateView().stateLayoutConfig.disableOperationWhenRequesting(disable)
return checkMultiStateView().stateLayoutConfig
}
override fun getProcessor(): StateProcessor {
return checkMultiStateView().stateLayoutConfig.processor
}
override fun setMessageGravity(state: Int, gravity: Int): StateLayoutConfig {
checkMultiStateView().stateLayoutConfig.setMessageGravity(state, gravity)
return this
}
private fun checkMultiStateView(): StateLayout {
return _multiStateView
?: throw IllegalStateException("Calling this function requires defining a view that implements StateLayout in the Layout")
}
}

@ -10,6 +10,7 @@ import com.android.base.app.ui.RefreshView;
import com.android.base.app.ui.RefreshViewFactory;
import com.android.base.app.ui.StateLayout;
import com.android.base.app.ui.StateLayoutConfig;
import com.android.base.widget.StateProcessor;
import static com.android.base.app.ui.CommonId.REFRESH_ID;
import static com.android.base.app.ui.CommonId.STATE_ID;
@ -149,6 +150,12 @@ final class RefreshableStateLayoutImpl implements RefreshStateLayout, StateLayou
return this;
}
@Override
public StateLayoutConfig setMessageGravity(int state, int gravity) {
checkMultiStateView().getStateLayoutConfig().setMessageGravity(state, gravity);
return this;
}
@Override
public StateLayoutConfig setStateIcon(@RetryableState int state, Drawable drawable) {
checkMultiStateView().getStateLayoutConfig().setStateIcon(state, drawable);
@ -179,6 +186,11 @@ final class RefreshableStateLayoutImpl implements RefreshStateLayout, StateLayou
return this;
}
@Override
public StateProcessor getProcessor() {
return checkMultiStateView().getStateLayoutConfig().getProcessor();
}
private StateLayout checkMultiStateView() {
if (mMultiStateView == null) {
throw new IllegalStateException("Calling this function requires defining a view that implements StateLayout in the Layout");

@ -4,6 +4,8 @@ import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import com.android.base.widget.StateProcessor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -50,6 +52,8 @@ public interface StateLayoutConfig {
StateLayoutConfig setStateMessage(@RetryableState int state, CharSequence message);
StateLayoutConfig setMessageGravity(@RetryableState int state, int gravity);
StateLayoutConfig setStateIcon(@RetryableState int state, Drawable drawable);
StateLayoutConfig setStateIcon(@RetryableState int state, @DrawableRes int drawableId);
@ -60,4 +64,6 @@ public interface StateLayoutConfig {
StateLayoutConfig disableOperationWhenRequesting(boolean disable);
StateProcessor getProcessor();
}

@ -4,6 +4,7 @@ package com.android.base.app.ui
import com.android.base.app.BaseKit
import com.android.base.utils.common.Checker
import timber.log.Timber
fun <T> RefreshListLayout<T>.processListResultWithStatus(list: List<T>?, onEmpty: (() -> Unit)? = null) {
if (isLoadingMore) {
@ -136,7 +137,11 @@ fun <T> RefreshStateLayout.processResultWithStatus(t: T?, onResult: ((T) -> Unit
}
}
fun RefreshStateLayout.processErrorWithStatus(throwable: Throwable) {
fun RefreshStateLayout.processErrorWithStatus(throwable: Throwable?) {
if (throwable == null) {
Timber.d("processErrorWithStatus called, but throwable is null")
return
}
if (isRefreshing) {
refreshCompleted()
}

@ -15,13 +15,11 @@ public class Resource<T> {
private final Throwable mError;
private final Status mStatus;
private final T mData; //data or default data
private final T mDefaultData; //data or default data
private Resource(Throwable error, T data, T defaultData, Status status) {
private Resource(Throwable error, T data, Status status) {
mError = error;
mStatus = status;
mData = data;
mDefaultData = defaultData;
}
public boolean isSuccess() {
@ -45,27 +43,33 @@ public class Resource<T> {
}
public static <T> Resource<T> success() {
return new Resource<>(null, null, null, Status.SUCCESS);
return new Resource<>(null, null, Status.SUCCESS);
}
public static <T> Resource<T> success(@Nullable T t) {
return new Resource<>(null, t, null, Status.SUCCESS);
public static <T> Resource<T> success(@Nullable T data) {
return new Resource<>(null, data, Status.SUCCESS);
}
public static <T> Resource<T> error(@NonNull Throwable error) {
return error(error, null);
}
/**
* 创建一个 error 状态且设置一个默认的数据
*/
public static <T> Resource<T> error(@NonNull Throwable error, T defaultValue) {
return new Resource<>(error, null, defaultValue, Status.ERROR);
return new Resource<>(error, defaultValue, Status.ERROR);
}
public static <T> Resource<T> loading() {
return loading(null);
}
/**
* 创建一个 loading 状态且设置一个默认的数据
*/
public static <T> Resource<T> loading(T defaultValue) {
return new Resource<>(null, null, defaultValue, Status.LOADING);
return new Resource<>(null, defaultValue, Status.LOADING);
}
/**
@ -74,9 +78,16 @@ public class Resource<T> {
* @return Resource
*/
public static Resource noChange() {
return new Resource<>(null, null, null, Status.NOT_CHANGED);
return new Resource<>(null, null, Status.NOT_CHANGED);
}
/**
* 获取 Resource 中保存的数据只有在 success 状态并且存在数据时下才能调用此方法否则将抛出异常
*
* @return Resource 中保存的数据
* @throws UnsupportedOperationException success 状态调用此方法
* @throws NullPointerException Resource 中没有保存数据时调用此方法
*/
@NonNull
public T data() {
if (isError() || isLoading() || isNoChange()) {
@ -88,17 +99,40 @@ public class Resource<T> {
return mData;
}
/**
* 获取 Resource 中保存的数据如果不存在数据则返回 defaultData 所设置的默认数据在不同状态下获取的数据具有不同的意义
*
* <pre>
* <li>success 状态下返回一个成功操作所产生的数据</li>
* <li>error 状态下返回一个默认的数据如果存在的话</li>
* <li>loading 状态下返回一个默认的数据如果存在的话</li>
* </pre>
*
* @param defaultData 如果不存在数据则返回 defaultData 所设置的默认数据
* @return Resource 中保存的数据
*/
@Nullable
public T orElse(@Nullable T elseData) {
public T orElse(@Nullable T defaultData) {
if (mData == null) {
return elseData;
return defaultData;
}
return mData;
}
/**
* 获取 Resource 中保存的数据在不同状态下获取的数据具有不同的意义
*
* <pre>
* <li>success 状态下返回一个成功操作所产生的数据</li>
* <li>error 状态下返回一个默认的数据如果存在的话</li>
* <li>loading 状态下返回一个默认的数据如果存在的话</li>
* </pre>
*
* @return Resource 中保存的数据
*/
@Nullable
public T defaultData() {
return mDefaultData;
public T get() {
return mData;
}
public Throwable error() {
@ -112,7 +146,6 @@ public class Resource<T> {
"mError=" + mError +
", mStatus=" + mStatus +
", mData=" + mData +
", mDefaultData=" + mDefaultData +
'}';
}

@ -1,6 +1,6 @@
package com.android.base.data
/**when in loading*/
inline fun <T> Resource<T>.onLoading(onLoading: () -> Unit): Resource<T> {
if (this.isLoading) {
onLoading()
@ -8,6 +8,7 @@ inline fun <T> Resource<T>.onLoading(onLoading: () -> Unit): Resource<T> {
return this
}
/**when error occurred*/
inline fun <T> Resource<T>.onError(onError: (error: Throwable) -> Unit): Resource<T> {
if (this.isError) {
onError(error())
@ -15,6 +16,7 @@ inline fun <T> Resource<T>.onError(onError: (error: Throwable) -> Unit): Resourc
return this
}
/**when no change*/
inline fun <T> Resource<T>.onNoChange(onNoChange: () -> Unit): Resource<T> {
if (this.isNoChange) {
onNoChange()
@ -22,7 +24,7 @@ inline fun <T> Resource<T>.onNoChange(onNoChange: () -> Unit): Resource<T> {
return this
}
/**success*/
/**when succeeded*/
inline fun <T> Resource<T>.onSuccess(onSuccess: (data: T?) -> Unit): Resource<T> {
if (this.isSuccess) {
onSuccess(this.orElse(null))
@ -30,10 +32,20 @@ inline fun <T> Resource<T>.onSuccess(onSuccess: (data: T?) -> Unit): Resource<T>
return this
}
/**success with data*/
/**when succeeded and has data*/
inline fun <T> Resource<T>.onSuccessWithData(onSuccess: (data: T) -> Unit): Resource<T> {
if (this.isSuccess && this.hasData()) {
onSuccess(this.data())
val t = this.get()
if (this.isSuccess && t != null) {
onSuccess(t)
}
return this
}
}
val <T> Resource<T>?.isFailed
get() = this != null && this.isError
val <T> Resource<T>?.isSucceeded
get() = this != null && this.isSuccess
val <T> Resource<T>?.inLoading
get() = this != null && this.isLoading

@ -26,7 +26,7 @@ import static com.android.base.app.ui.StateLayoutConfig.ViewState;
*/
public class SimpleMultiStateView extends MultiStateView implements StateLayout {
private StateActionProcessor mStateActionProcessor;
private StateProcessor mStateProcessor;
private StateListener mStateListener;
public SimpleMultiStateView(Context context) {
@ -45,8 +45,8 @@ public class SimpleMultiStateView extends MultiStateView implements StateLayout
initProcessor(typedArray);
mStateActionProcessor.onInitialize(this);
mStateActionProcessor.onParseAttrs(typedArray);
mStateProcessor.onInitialize(this);
mStateProcessor.onParseAttrs(typedArray);
typedArray.recycle();
}
@ -57,15 +57,15 @@ public class SimpleMultiStateView extends MultiStateView implements StateLayout
if (!StringChecker.isEmpty(processorPath)) {
try {
Class<?> processorClass = Class.forName(processorPath);
mStateActionProcessor = (StateActionProcessor) processorClass.newInstance();
mStateProcessor = (StateProcessor) processorClass.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
Timber.e("initProcessor() called can not instance processor: " + processorPath);
}
}
if (mStateActionProcessor == null) {
mStateActionProcessor = new StateActionProcessor();
if (mStateProcessor == null) {
mStateProcessor = new StateActionProcessor();
}
}
@ -89,7 +89,7 @@ public class SimpleMultiStateView extends MultiStateView implements StateLayout
}
private void processStateInflated(@ViewState int viewState, @NonNull View view) {
mStateActionProcessor.processStateInflated(viewState, view);
mStateProcessor.processStateInflated(viewState, view);
}
@Override
@ -139,7 +139,7 @@ public class SimpleMultiStateView extends MultiStateView implements StateLayout
@Override
public StateLayoutConfig getStateLayoutConfig() {
return mStateActionProcessor.getStateLayoutConfigImpl();
return mStateProcessor.getStateLayoutConfigImpl();
}
}

@ -27,7 +27,7 @@ import static com.android.base.app.ui.StateLayoutConfig.SERVER_ERROR;
* Email: ztiany3@gmail.com
* Date : 2018-05-17 17:08
*/
public class StateActionProcessor implements StateProcessor {
public class StateActionProcessor extends StateProcessor {
private OnRetryActionListener mOnRetryActionListener;
@ -102,6 +102,7 @@ public class StateActionProcessor implements StateProcessor {
private final int mState;
private Drawable mDrawable;
private CharSequence mMessage;
private int mMessageGravity;
private CharSequence mActionText;
private View mStateView;
private TextView mMessageTv;
@ -125,6 +126,7 @@ public class StateActionProcessor implements StateProcessor {
setActionText(mActionText);
setMessage(mMessage);
setDrawable(mDrawable);
setMessageGravity(mMessageGravity);
}
void setDrawable(Drawable drawable) {
@ -141,6 +143,13 @@ public class StateActionProcessor implements StateProcessor {
}
}
void setMessageGravity(int gravity) {
mMessageGravity = gravity;
if (mMessageTv != null) {
mMessageTv.setGravity(mMessageGravity);
}
}
void setActionText(CharSequence actionText) {
mActionText = actionText;
if (mActionBtn == null) {
@ -163,6 +172,12 @@ public class StateActionProcessor implements StateProcessor {
return this;
}
@Override
public StateLayoutConfig setMessageGravity(int state, int gravity) {
getViewInfoForState(state).setMessageGravity(gravity);
return this;
}
@Override
public StateLayoutConfig setStateIcon(@ViewState int state, Drawable drawable) {
getViewInfoForState(state).setDrawable(drawable);
@ -192,6 +207,12 @@ public class StateActionProcessor implements StateProcessor {
mSimpleMultiStateView.setDisableOperationWhenRequesting(disable);
return this;
}
@Override
public StateProcessor getProcessor() {
return StateActionProcessor.this;
}
};
}
}

@ -11,14 +11,14 @@ import com.android.base.app.ui.StateLayoutConfig;
* Email: ztiany3@gmail.com
* Date : 2018-05-17 17:25
*/
interface StateProcessor {
public abstract class StateProcessor {
void onInitialize(SimpleMultiStateView simpleMultiStateView);
protected abstract void onInitialize(SimpleMultiStateView simpleMultiStateView);
void onParseAttrs(TypedArray typedArray);
protected abstract void onParseAttrs(TypedArray typedArray);
void processStateInflated(@StateLayoutConfig.ViewState int viewState, @NonNull View view);
protected abstract void processStateInflated(@StateLayoutConfig.ViewState int viewState, @NonNull View view);
StateLayoutConfig getStateLayoutConfigImpl();
protected abstract StateLayoutConfig getStateLayoutConfigImpl();
}

Loading…
Cancel
Save