diff --git a/lib_base/src/main/java/com/android/base/app/fragment/RefreshLoadMoreStateLayoutImpl.kt b/lib_base/src/main/java/com/android/base/app/fragment/RefreshLoadMoreStateLayoutImpl.kt index 0ba52b2..59c6599 100644 --- a/lib_base/src/main/java/com/android/base/app/fragment/RefreshLoadMoreStateLayoutImpl.kt +++ b/lib_base/src/main/java/com/android/base/app/fragment/RefreshLoadMoreStateLayoutImpl.kt @@ -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(CommonId.STATE_ID) as StateLayout - private var mRefreshView: RefreshLoadMoreView + private var _multiStateView: StateLayout? = layout.findViewById(CommonId.STATE_ID) as? StateLayout + private var _refreshView: RefreshLoadMoreView val refreshView: RefreshLoadMoreView - get() = mRefreshView + get() = _refreshView init { - val refreshLayout = mLayout.findViewById(CommonId.REFRESH_ID) - mRefreshView = RefreshLoadViewFactory.createRefreshView(refreshLayout) + val refreshLayout = layout.findViewById(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") } } \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/app/fragment/RefreshableStateLayoutImpl.java b/lib_base/src/main/java/com/android/base/app/fragment/RefreshableStateLayoutImpl.java index 638f62d..5fe8cdb 100644 --- a/lib_base/src/main/java/com/android/base/app/fragment/RefreshableStateLayoutImpl.java +++ b/lib_base/src/main/java/com/android/base/app/fragment/RefreshableStateLayoutImpl.java @@ -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"); diff --git a/lib_base/src/main/java/com/android/base/app/ui/StateLayoutConfig.java b/lib_base/src/main/java/com/android/base/app/ui/StateLayoutConfig.java index 052f34a..7c5d154 100644 --- a/lib_base/src/main/java/com/android/base/app/ui/StateLayoutConfig.java +++ b/lib_base/src/main/java/com/android/base/app/ui/StateLayoutConfig.java @@ -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(); + } diff --git a/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt b/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt index d13e9e0..1c7ec40 100644 --- a/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt +++ b/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt @@ -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 RefreshListLayout.processListResultWithStatus(list: List?, onEmpty: (() -> Unit)? = null) { if (isLoadingMore) { @@ -136,7 +137,11 @@ fun 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() } diff --git a/lib_base/src/main/java/com/android/base/data/Resource.java b/lib_base/src/main/java/com/android/base/data/Resource.java index f0be229..251679e 100644 --- a/lib_base/src/main/java/com/android/base/data/Resource.java +++ b/lib_base/src/main/java/com/android/base/data/Resource.java @@ -15,13 +15,11 @@ public class Resource { 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 { } public static Resource success() { - return new Resource<>(null, null, null, Status.SUCCESS); + return new Resource<>(null, null, Status.SUCCESS); } - public static Resource success(@Nullable T t) { - return new Resource<>(null, t, null, Status.SUCCESS); + public static Resource success(@Nullable T data) { + return new Resource<>(null, data, Status.SUCCESS); } public static Resource error(@NonNull Throwable error) { return error(error, null); } + /** + * 创建一个 error 状态,且设置一个默认的数据 + */ public static Resource error(@NonNull Throwable error, T defaultValue) { - return new Resource<>(error, null, defaultValue, Status.ERROR); + return new Resource<>(error, defaultValue, Status.ERROR); } public static Resource loading() { return loading(null); } + /** + * 创建一个 loading 状态,且设置一个默认的数据 + */ public static Resource 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 { * @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 { return mData; } + /** + * 获取 Resource 中保存的数据,如果不存在数据则返回 defaultData 所设置的默认数据,在不同状态下获取的数据具有不同的意义: + * + *
+     *     
  • success 状态下,返回一个成功操作所产生的数据
  • + *
  • error 状态下,返回一个默认的数据,如果存在的话
  • + *
  • loading 状态下,返回一个默认的数据,如果存在的话
  • + *
    + * + * @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 中保存的数据,在不同状态下获取的数据具有不同的意义: + * + *
    +     *     
  • success 状态下,返回一个成功操作所产生的数据
  • + *
  • error 状态下,返回一个默认的数据,如果存在的话
  • + *
  • loading 状态下,返回一个默认的数据,如果存在的话
  • + *
    + * + * @return Resource 中保存的数据。 + */ @Nullable - public T defaultData() { - return mDefaultData; + public T get() { + return mData; } public Throwable error() { @@ -112,7 +146,6 @@ public class Resource { "mError=" + mError + ", mStatus=" + mStatus + ", mData=" + mData + - ", mDefaultData=" + mDefaultData + '}'; } diff --git a/lib_base/src/main/java/com/android/base/data/Resource.kt b/lib_base/src/main/java/com/android/base/data/Resource.kt index 0ca07e0..91f1974 100644 --- a/lib_base/src/main/java/com/android/base/data/Resource.kt +++ b/lib_base/src/main/java/com/android/base/data/Resource.kt @@ -1,6 +1,6 @@ package com.android.base.data - +/**when in loading*/ inline fun Resource.onLoading(onLoading: () -> Unit): Resource { if (this.isLoading) { onLoading() @@ -8,6 +8,7 @@ inline fun Resource.onLoading(onLoading: () -> Unit): Resource { return this } +/**when error occurred*/ inline fun Resource.onError(onError: (error: Throwable) -> Unit): Resource { if (this.isError) { onError(error()) @@ -15,6 +16,7 @@ inline fun Resource.onError(onError: (error: Throwable) -> Unit): Resourc return this } +/**when no change*/ inline fun Resource.onNoChange(onNoChange: () -> Unit): Resource { if (this.isNoChange) { onNoChange() @@ -22,7 +24,7 @@ inline fun Resource.onNoChange(onNoChange: () -> Unit): Resource { return this } -/**success*/ +/**when succeeded*/ inline fun Resource.onSuccess(onSuccess: (data: T?) -> Unit): Resource { if (this.isSuccess) { onSuccess(this.orElse(null)) @@ -30,10 +32,20 @@ inline fun Resource.onSuccess(onSuccess: (data: T?) -> Unit): Resource return this } -/**success with data*/ +/**when succeeded and has data*/ inline fun Resource.onSuccessWithData(onSuccess: (data: T) -> Unit): Resource { - if (this.isSuccess && this.hasData()) { - onSuccess(this.data()) + val t = this.get() + if (this.isSuccess && t != null) { + onSuccess(t) } return this -} \ No newline at end of file +} + +val Resource?.isFailed + get() = this != null && this.isError + +val Resource?.isSucceeded + get() = this != null && this.isSuccess + +val Resource?.inLoading + get() = this != null && this.isLoading \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java b/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java index 3f47d7e..f981ddb 100644 --- a/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java +++ b/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java @@ -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(); } } diff --git a/lib_base/src/main/java/com/android/base/widget/StateActionProcessor.java b/lib_base/src/main/java/com/android/base/widget/StateActionProcessor.java index 1001b67..ba2032a 100644 --- a/lib_base/src/main/java/com/android/base/widget/StateActionProcessor.java +++ b/lib_base/src/main/java/com/android/base/widget/StateActionProcessor.java @@ -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; + } + }; -} +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/widget/StateProcessor.java b/lib_base/src/main/java/com/android/base/widget/StateProcessor.java index f094a73..7821c8d 100644 --- a/lib_base/src/main/java/com/android/base/widget/StateProcessor.java +++ b/lib_base/src/main/java/com/android/base/widget/StateProcessor.java @@ -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(); }