您的位置:首页 > 移动开发 > Android开发

Android中的MVC设计

2016-02-17 11:50 666 查看

1. 前言,以前在开发j2ee的时候有那种比较完善的开发框架,例如spring mvc,所以项目架构非常清晰,基本做到了数据展示与数据获取完全分离,严格的遵守了MVC的框架模式,项目可维护性高,新进开发人员理解上手容易;后来转到android端开发,我发现android端并没有非常明显的MVC架构,因为Activity中数据展示和数据获取都可以写在一起的,也就是说Activity扮演了View和Controller的角色,因为往往是这样的:Activity中的事件响应直接去http请求或者搜索本地数据库,http请求和数据库搜索是封装起来的,但是它们返回的结果往往是通过回调得到的,而回调必须是在Activity中调用的,所以还是导致在Activity中有一大段数据处理代码,其实我认为Activity最纯粹的就应该只做数据展示和UI变化。

2. 我们团队的项目中是这么改善如上的问题的。

一切界面的初始化数据都是通过从数据库中搜索出来展示的;

所有的HTTP请求回来的数据都最先保存到本地数据库中;

数据库中的表的数据如果发生改变了之后就通知到界面,让界面及时更新数据显示;

我们做了如下实现:

DaoListener是一个数据表监听

public class DaoListener {

private DaoThreadMode daoThreadMode = DaoThreadMode.MainThread;

public void onDataChanged(int daoOperationType, Object data){}

public void onDataChanged(Object data){}

protected DaoThreadMode getDaoThreadMode() {
return daoThreadMode;
}

protected void setDaoThreadMode(DaoThreadMode daoThreadMode) {
this.daoThreadMode = daoThreadMode;
}
}


DaoObserver是数据表的观察者,一旦表数据发生改变就立刻发布通知

public class DaoObserver {

private static List<DaoListener> listeners = new ArrayList<>();

private static Handler uiHandler = new Handler(Looper.getMainLooper());

private static Handler asyncHandler;

private static HandlerThread handlerThread;

static {
handlerThread = new HandlerThread("backgroud_thread");
handlerThread.start();
asyncHandler = new Handler(handlerThread.getLooper());
}

public static void regist(DaoListener daoListener) {
daoListener.setDaoThreadMode(DaoThreadMode.MainThread);
regist(daoListener, DaoThreadMode.MainThread);
}

public static void regist(DaoListener daoListener, DaoThreadMode daoThreadMode) {
daoListener.setDaoThreadMode(daoThreadMode);
listeners.add(daoListener);
}

public static void unRegist(DaoListener daoListener) {
listeners.remove(daoListener);
}

/**
* 回调将保证在主线程中执行,禁止执行耗时任务,若执行耗时任务则要另开线程
*
* @param data
*/
public static synchronized void publish(int daoOperationType, Object data) {
notifyDataChanged(daoOperationType, data);
}

private static void notifyDataChanged(final int daoOperationType, final Object data) {
for (final DaoListener daoListener : listeners) {
DaoThreadMode daoThreadMode = daoListener.getDaoThreadMode();
if (daoThreadMode == DaoThreadMode.MainThread) {
uiHandler.post(new Runnable() {
@Override
public void run() {
onDataChanged(daoListener, daoOperationType, data);
}
});
} else if (daoThreadMode == DaoThreadMode.BackgroundThread) {
if (Looper.myLooper() == Looper.getMainLooper()) {
asyncHandler.post(new Runnable() {
@Override
public void run() {
onDataChanged(daoListener, daoOperationType, data);
}
});
} else {
onDataChanged(daoListener, daoOperationType, data);
}
} else if (daoThreadMode == DaoThreadMode.Async) {
asyncHandler.post(new Runnable() {
@Override
public void run() {
onDataChanged(daoListener, daoOperationType, data);
}
});
} else {
// PostThread线程模式
onDataChanged(daoListener, daoOperationType, data);
}
}
}

private static void onDataChanged(DaoListener daoListener, int daoOperationType, Object data) {
daoListener.onDataChanged(daoOperationType, data);
daoListener.onDataChanged(data);
}
}


DaoOperation数据表更新的操作,增删查改

public interface DaoOperation {

int INSERT = 1;
int DELETE = 2;
int UPDATE = 3;
int SELECT = 4;
int INSERT_BATCH = 5;
int DELETE_BATCH = 6;
int UPDATE_BATCH = 7;
}


DaoThreadMode数据表更新回调的线程模型

public enum DaoThreadMode {

/**
* 同一个线程
*/
PostThread,

/**
* 主线程
*/
MainThread,

/**
* 后台线程
*/
BackgroundThread,

/**
* 单独开一个线程
*/
Async
}


而在Activity中就做如下实现:

public class TestActivity extends Activity {

DaoListener daoListener = new DaoListener() {
@Override
public void onDataChanged(Object data) {
if (data instanceof Object) {
changeUI();
} else if (data instanceof Location) {
showData();
} else {
// other type of data
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaoObserver.regist(daoListener);
}

@Override
protected void onDestroy() {
super.onDestroy();
DaoObserver.unRegist(daoListener);
}

private void changeUI() {
// do something
}

private void showData() {
// do something
}
}


我们的项目的数据库操作是采用ormlite,每个数据表都对应一个实体bean和一个dao,这个dao继承一个表操作的基类dao,在基类dao里面才实现真正的增删查改并且检测表数据更新,发布更新通知到DaoListener,这样做的好处在于把所有的界面数据更新的触发点统一在一起了而不是像以前一样分散在各自的方法中;例如Activity里面有个方法去请求Http数据,那它直接在回调中把数据插入到数据库,这样在DaoListener会收到数据更新的通知,并且会把最新的数据以Object对象的形式传递过来,可根据区分Object的类型来对各个Http请求进行区别。



优点是:界面数据更新触发统一在一起,避免出现http请求数据成功并刷新界面成功,但是插入数据库失败导致界面数据和数据库中的数据不一致;把Http请求和数据刷新操作隔离开来。

缺点是:如果在DaoListener再次做数据库更新操作有可能造成递归反之程序严重卡顿,造成性能问题,之前遇到过,只要不再DaoListener做数据库操作就没有问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: