Android LCE架构设计
LCE架构,按拆字法解析:L:Loading加载,C:Content加载内容,E:Error加载失败。
LCE架构使用最为常见的场景是做列表数据的加载,在加载时,如果隔壁老王占用了你的带宽,那么数据加载会变的很慢,为了不让用户觉得等待漫长,可以出现一个加载场景;当数据加载成功时,将数据显示在UI上;如果数据加载失败,可以显示一个加载失败的页面或者图片,这就是LCE的使用场景。
根据上面的需求分析,可以大概的了解到LCE需要的组成部分:动画,场景体现(不同场景的UI显示)。动画主要在三个方便体现:加载中,加载成功,加载失败。场景体现主要有五个方面的体现:显示loading,显示数据内容,显示加载失败,加载数据和绑定数据。那么久先来定义两个接口:
动画接口:
public interface ILceAnimator {
void showLoading(View loadingView, View contentView, View errorView);
void showErrorView(View loadingView, View contentView, View errorView);
void showContent(View loadingView, View contentView, View errorView);
}
场景接口:
public interface LceView<M> extends IView {
/**
* 显示loading页面 pullToRefresh:true代表你用的是下拉刷新组件
*
* @param pullToRefresh
*/
void showLoading(boolean pullToRefresh);
/**
* 显示ContentView
*/
void showContent();
/**
* 显示异常界面
*/
void showError();
/**
* 绑定数据
*
* @param data
*/
void bindData(M data);
/**
* 加载数据
*
* @param pullToRefresh
*/
void loadData(boolean pullToRefresh);
}
为了方便使用,可以提供一个默认的动画和场景实现。
默认的LCE场景实现:
public class LceViewImpl<M> implements LceView<M> {
private View loadingView;
private View contentView;
private View errorView;
private ILceAnimator lceAnimator;
/**
* 初始化视图
*
* @param v
*/
public void initLceView(View v) {
if (loadingView == null) {
loadingView = v.findViewById(R.id.loadingView);
}
if (contentView == null) {
contentView = v.findViewById(R.id.contentView);
}
if (errorView == null) {
errorView = v.findViewById(R.id.errorView);
}
if (loadingView == null) {
throw new NullPointerException("loadingView is not null!");
}
if (contentView == null) {
throw new NullPointerException("contentView is not null!");
}
if (errorView == null) {
throw new NullPointerException("errorView is not null!");
}
}
/**
* 添加重写加载监听
*
* @param onClickListener
*/
public void setOnErrorViewClickListener(OnClickListener onClickListener) {
if (this.errorView != null) {
this.errorView.setOnClickListener(onClickListener);
}
}
private ILceAnimator getLceAnimator() {
if (lceAnimator == null) {
lceAnimator = DefaultLceAnimator.getInstance();
}
return lceAnimator;
}
/**
* 绑定动画执行策略
*
* @param lceAnimator
*/
public void setLceAnimator(ILceAnimator lceAnimator) {
this.lceAnimator = lceAnimator;
}
/**
* 注意:记得加判断,因为下拉刷新组件有正在加载头部视图,不需要显示加载过程了
* @param pullToRefresh
*/
@Override
public void showLoading(boolean pullToRefresh) {
if(!pullToRefresh){
getLceAnimator().showLoading(loadingView, contentView, errorView);
}
}
@Override
public void showContent() {
getLceAnimator().showContent(loadingView, contentView, errorView);
}
@Override
public void showError() {
getLceAnimator().showErrorView(loadingView, contentView, errorView);
}
@Override
public void bindData(M data) {
}
@Override
public void loadData(boolean pullToRefresh) {
}
}
默认的动画实现:
@SuppressLint("NewApi")
public class DefaultLceAnimator implements ILceAnimator {
private volatile static DefaultLceAnimator lceAnimator;
public DefaultLceAnimator() {
}
public static DefaultLceAnimator getInstance() {
if (lceAnimator == null) {
synchronized (AnimatorUtils.class) {
if (lceAnimator == null) {
lceAnimator = new DefaultLceAnimator();
}
}
}
return lceAnimator;
}
@Override
public void showLoading(View loadingView, View contentView, View errorView) {
contentView.setVisibility(View.GONE);
errorView.setVisibility(View.GONE);
loadingView.setVisibility(View.VISIBLE);
}
@Override
public void showErrorView(final View loadingView,final View contentView,final View errorView) {
contentView.setVisibility(View.GONE);
final Resources resources = loadingView.getResources();
// Not visible yet, so animate the view in
AnimatorSet set = new AnimatorSet();
ObjectAnimator in = ObjectAnimator.ofFloat(errorView, "alpha", 1f);
ObjectAnimator loadingOut = ObjectAnimator.ofFloat(loadingView,
"alpha", 0f);
set.playTogether(in, loadingOut);
set.setDuration(resources
.getInteger(R.integer.lce_error_view_show_animation_time));
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
errorView.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
loadingView.setVisibility(View.GONE);
loadingView.setAlpha(1f); // For future showLoading calls
}
});
set.start();
}
@Override
public void showContent(final View loadingView,final View contentView,final View errorView) {
if (contentView.getVisibility() == View.VISIBLE) {
errorView.setVisibility(View.GONE);
loadingView.setVisibility(View.GONE);
} else {
errorView.setVisibility(View.GONE);
final Resources resources = loadingView.getResources();
final int translateInPixels = resources
.getDimensionPixelSize(R.dimen.lce_content_view_animation_translate_y);
// Not visible yet, so animate the view in
AnimatorSet set = new AnimatorSet();
ObjectAnimator contentFadeIn = ObjectAnimator.ofFloat(contentView,
"alpha", 0f, 1f);
ObjectAnimator contentTranslateIn = ObjectAnimator.ofFloat(
contentView, "translationY", translateInPixels, 0);
ObjectAnimator loadingFadeOut = ObjectAnimator.ofFloat(loadingView,
"alpha", 1f, 0f);
ObjectAnimator loadingTranslateOut = ObjectAnimator.ofFloat(
loadingView, "translationY", 0, -translateInPixels);
set.playTogether(contentFadeIn, contentTranslateIn, loadingFadeOut,
loadingTranslateOut);
set.setDuration(resources
.getInteger(R.integer.lce_content_view_show_animation_time));
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
contentView.setTranslationY(0);
loadingView.setTranslationY(0);
contentView.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
loadingView.setVisibility(View.GONE);
loadingView.setAlpha(1f); // For future showLoading calls
contentView.setTranslationY(0);
loadingView.setTranslationY(0);
}
});
set.start();
}
}
}
在集成LCE的时候,如果没有提供自定的实现,那么就是用默认的实现。
Fragment LCE集成实现:
public abstract class LceFragment<M> extends Fragment implements LceView<M> {
// 初始化Lce UI布局(规定你的Lce布局文件的id)
private LceViewImpl<M> lceViewImpl;
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (lceViewImpl == null) {
lceViewImpl = new MvpLceViewImpl<M>();
}
initLceView(view);
}
private void initLceView(View v) {
lceViewImpl.initLceView(v);
lceViewImpl.setOnErrorViewClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
onErrorClick();
}
});
}
public void setLceAnimator(ILceAnimator lceAnimator){
lceViewImpl.setLceAnimator(lceAnimator);
}
@Override
public void showLoading(boolean pullToRefresh) {
lceViewImpl.showLoading(pullToRefresh);
}
@Override
public void showContent() {
lceViewImpl.showContent();
}
@Override
public void showError() {
lceViewImpl.showError();
}
@Override
public void loadData(boolean pullToRefresh) {
lceViewImpl.loadData(pullToRefresh);
}
@Override
public void bindData(M data) {
lceViewImpl.bindData(data);
}
public void onErrorClick() {
loadData(false);
}
}
当然也可以将LCE集成到Activity中。