重构的原因:
代码拓展困难,重复代码多,逻辑复杂,不容易理解,在持续迭代的项目开发中可测试性丧失。
重构的目的;
显然就是解决上述的问题
目前在项目中遇到的一个案例;
项目中用到一个开源控件PullToRefresh,在版本迭代中,使用方式是需要调用的页面直接在布局文件中直接调用,然后在Actvity和fragment中获取这个View,设置监听等。
引起的问题;
在布局中需要重复的定义一些属性,在代码中需要重复的设置监听,最重要的是,此开源控件已经不能满足项目的需要,需要替换成新的合适的PullToRefresh开源控件,这将导致修改大量的代码和布局文件。
解决的思路
1.首先要总结出一套PullToRefresh的共同特性
2.将这些特性使用一套接口封装起来,然后使用一个Impl类来实现它,代码中只需要调用这些接口,而不需要关心具体的实现类。
3.以后若再需要替换新的控件,只需要修改Impl类,还有一些其他的少量代码,这是重构的目标。
PullToRefresh的特性:支持上拉和下拉刷新,支持手动停止刷新,支持设置刷新的模式(未来还需要支持自动刷新)
支持常用的三个控件:ListView,ScrollView,GridView,需要封装这三种类型的View,以便在布局中直接引用,以后若需要替换新的开源控件,则可针对此三个自定义的View操作,而不需要修改调用的布局。
拓展:封装 fragment和activity,只需要少量的代码即可使用PullToRefresh,简化代码。
PtrBase接口:设置监听,设置刷新模式,获取刷新的view,获取包装刷新的View
import android.view.View;
/**
* Created by whuthm on 2015/12/2.
*/
public interface PtrBase {
void setPtrMode(PtrMode mode);
void setOnRefreshListener(OnRefreshListener l);
View getRefreshableView();
View getRefreshableViewWrapper();
void finishRefresh(boolean success);
public enum PtrMode {
DISABLED, PULL_FROM_START, PULL_FROM_END, BOTH
}
}
OnRefreshListener:下拉或者上拉刷新监听
package com.whuthm.base.view.ptr;
/**
* Created by whuthm on 2015/12/2.
*/
public interface OnRefreshListener {
public void onRefreshFromStart();
public void onRefreshFromEnd();
}
package com.whuthm.base.view.ptr;
/**
* Created by whuthm on 2015/12/2.
*/
public interface PtrBaseView {
PtrBase getPtrBase();
}
PtrBaseImpl:具体的实现类,和第三方控件具体关联的地方,方便替换新的控件
import android.content.Context;
import android.text.format.DateUtils;
import android.view.View;
import android.widget.LinearLayout;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.whutm.base.NetworkTime;
/**
* Created by whuthm on 2015/12/2.
*/
class PtrBaseImpl implements PtrBase {
PullToRefreshBase mPullToRefreshBase;
long mLastUpdateTime;
OnRefreshListener mOnRefreshListener;
PtrBaseImpl(PullToRefreshBase pullToRefreshBase) {
mPullToRefreshBase = pullToRefreshBase;
mPullToRefreshBase.setOrientation(LinearLayout.VERTICAL);
mLastUpdateTime = NetworkTime.currentTimeMillis();
mPullToRefreshBase.setPullToRefreshOverScrollEnabled(false);
mPullToRefreshBase
.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener() {
@Override
public void onRefresh(PullToRefreshBase refreshView) {
final Context context = refreshView.getContext();
String label = DateUtils.formatDateTime(context, mLastUpdateTime,
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_ABBREV_ALL);
// Update the LastUpdatedLabel
refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(
context.getString(R.string.last_update_time_text, label));
PullToRefreshBase.Mode curMode = refreshView.getCurrentMode();
if (curMode == PullToRefreshBase.Mode.PULL_FROM_START) {
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefreshFromStart();
}
}
else if (curMode == PullToRefreshBase.Mode.PULL_FROM_END) {
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefreshFromEnd();
}
}
}
});
}
@Override
public void setPtrMode(PtrMode mode) {
mPullToRefreshBase.setMode(getMode(mode));
}
@Override
public void setOnRefreshListener(OnRefreshListener l) {
mOnRefreshListener = l;
}
@Override
public View getRefreshableView() {
return mPullToRefreshBase.getRefreshableView();
}
@Override
public View getRefreshableViewWrapper() {
return mPullToRefreshBase;
}
@Override
public void finishRefresh(boolean success) {
if (success) {
mLastUpdateTime = NetworkTime.currentTimeMillis();
}
mPullToRefreshBase.onRefreshComplete();
}
private static PullToRefreshBase.Mode getMode(PtrMode mode) {
switch (mode) {
case DISABLED:
return PullToRefreshBase.Mode.DISABLED;
case PULL_FROM_END:
return PullToRefreshBase.Mode.PULL_FROM_END;
case BOTH:
return PullToRefreshBase.Mode.BOTH;
case PULL_FROM_START:
default:
return PullToRefreshBase.Mode.PULL_FROM_START;
}
}
}
PtrListView:供布局中使用,此处也和第三方控件关联,而且定义一个PtrBase
package com.whuthm.base.view.ptr;
import android.content.Context;
import android.util.AttributeSet;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
/**
* Created by whuthm on 2015/12/2.
*/
public class PtrListView extends PullToRefreshListView implements PtrBaseView{
private PtrBase mPtrBase;
public PtrListView(Context context) {
this(context, null);
}
public PtrListView(Context context, AttributeSet attrs) {
super(context, attrs);
mPtrBase = new PtrBaseImpl(this);
}
@Override
public PtrBase getPtrBase() {
return mPtrBase;
}
}
PtrScrollView
package com.whuthm.base.view.ptr;
import android.content.Context;
import android.util.AttributeSet;
import com.whuthm.base.R;
/**
* Created by whuthm on 2015/11/19.
*/
public class PtrScrollView extends
com.handmark.pulltorefresh.library.PullToRefreshScrollView implements PtrBaseView {
private int mMaximumPullScroll;
private PtrBase mPtrBase;
public PtrScrollView(Context context) {
this(context, null);
}
public PtrScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mPtrBase = new PtrBaseImpl(this);
}
@Override
protected int getMaximumPullScroll() {
if (mMaximumPullScroll <= 0) {
mMaximumPullScroll = getResources().getDimensionPixelSize(
R.dimen.maximum_default_pull_scroll);
}
return mMaximumPullScroll;
}
@Override
public PtrBase getPtrBase() {
return mPtrBase;
}
}
PtrGridView
package com.whuthm.base.view.ptr;
import android.content.Context;
import android.util.AttributeSet;
import com.handmark.pulltorefresh.library.PullToRefreshGridView;
/**
* Created by whuthm on 2015/12/2.
*/
public class PtrGridView extends PullToRefreshGridView implements PtrBaseView{
private PtrBase mPtrBase;
public PtrGridView(Context context) {
this(context, null);
}
public PtrGridView(Context context, AttributeSet attrs) {
super(context, attrs);
mPtrBase = new PtrBaseImpl(this);
}
@Override
public PtrBase getPtrBase() {
return mPtrBase;
}
}
若需要引用新的控件,只需要具体 修改PtrBaseImpl或者创建新的实现类,少量修改PtrListView三个控件。
使用方式
在布局中引用后,在Activity中 PtrBaseView view = (PtrBaseView) findViewById(R.id.ptr_list);
然后就可获得PtrBase,通过PtrBase设置监听,设置刷新模式,控制手动停止,获取具体的刷新view,操作简化
待拓展;进一步简化代码,封装到fragment或者activity,每次使用时直接用,不需要获取和设置监听