用户在观看完应用介绍页面之后,会点击进入应用按钮,这时由于用户是第一次运行,所以会弹出注册页面。如果是老用户,启动应用时,在Splash页面之后,如果应用记录着用户的登录信息,测直接进入主页面,如果从本地取不到用户登录信息,则将显示登录页面。
注册和登录功能看起来很简单,但是由于我们这里需要实现一个完整的应用支撑基础设施,因此需要分几个部分来进行。我们首先会讨论怎样创建并使用Activity中会用到的Model类,在这中间我们会采用Application对象作为中心信息仓库,每个Model类只是中心信息仓库的视图,便于对应的Activity类来使用;接着我们会讨论Activity类的基类,在其中包装诸如按回退键提示退出等功能;接着我们会讨论网络请求的实现,这里我们采用异步任务的方式来进行,协议采用Json Over Http,因此会顺便介绍Json的解析。
在进入正文之前,首先解释一个问题,我们什么时候检查版本更新。一般你可以在很多点来检查版本更新,我在这里采用进入主页面前检查版本更新,为什么这样做呢?因为在实际项目中,我们可能会有些小范围测试的版本,我们会采用灰度更新的机制,即只有一部分用户会收到更新通知,试用最新版本,如果反响很好,我们再向普通用户推出版本更新,因此检查版本更新放在了登录之后。
好了,我们先来看怎样实现MVC中的Model。我们首先在WkyLib工程中,定义Model的基类WkyModel,代码如下所示:
public class WkyModel {
public static WkyModel getInstance(String objectId, Class cls) {
if (models.containsKey(objectId)) {
return models.get(objectId);
}
WkyModel model = (WkyModel)WkyReflection.callPrivateConstructor(cls);
model.setObjectId(objectId);
Log.e("wky", "cls:" + cls.getCanonicalName() + "!");
if (null == model) {
model = new WkyModel();
}
models.put(objectId, model);
return model;
}
public static void removeObject(String objectId) {
models.remove(objectId);
}
public static void removeInstance(String objectId) {
models.remove(objectId);
}
/**
* 在Activity.onDestroy中调用,判断是否需要将实例从models中移除
* @return
* 【闫涛 2015.09.17】初始版本
*/
public boolean isShared() {
return isShared;
}
/**
* 如果想要在多个界面中使用同一个Model对象,则需要调用此函数,
* 将isShared设置为true,这时在Activity.onDestroy中就不会将本实例从models中移除了
* @param isShared
* 【闫涛 2015.09.17】初始版本
*/
public void setShared(boolean isShared) {
this.isShared = isShared;
}
public String getObjectId() {
return objectId;
}
public void setObjectId(String objectId) {
this.objectId = objectId;
}
private static HashMap<String, WkyModel> models = new HashMap<String, WkyModel>();
protected boolean isShared = false;
protected String objectId = null;
}
假设一个Activity有对应的Model类时,例如JysRegisgetrLoginActivity需要JysRegisterLoginModel类对象时,会通过调用getInstance方法来获取实例。每个Model类,可以同时存在多个实例,保存在models属性中。一般情况下,Activity在onCreate或在启动此Activity时,会生成一个Model类的实例,当该Activity退出时,在onDestroy回调函数中将该实例从models属性中移除。但是如果设置了isShared为ture时,则onDestroy方法中就不会移除此对象,就可以在不同的Activity实例中使用了。
在上面的代码中,我们用到了Java的反射机制,根据getInstance方法第二个参数的类,调用该类的私有无参数构造函数,生成该类的对象,我们引入了一个反射工具类WkyReflection,代码如下所示:
public class WkyReflection {
/**
* 调用类的私有无参数构造函数,生成该类对象并返回该对角
* 例子:
* WkyRegisterLoginModel model = (WkyRegisterLoginModel)WkyReflection.callPrivateConstructor(WkyRegisterLoginModel.class);
* @param cls
* @return
* 【闫涛 2015.09.17】初始版本
*/
public static Object callPrivateConstructor(Class cls) {
Constructor[] constructor = cls.getDeclaredConstructors();
constructor[0].setAccessible(true);
Object rst = null;
try {
rst = constructor[0].newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rst;
}
}
在本节开头我们就提到,我们的信息保存在应用的中心信息仓库中,每个Model里保存的,只是其中的一部分,在Android平台下,我们可以利用Application子类来作为中心信息仓库,代码如下所示:
/**
* model类将所有信息均保存在HashMap中,这样信息可以在Model之间共用
* @param key
* @param val
* 【闫涛 2015.09.17】初始版本
*/
public static void putObject(String key, Object val) {
params.put(key, val);
}
/**
* 从HashMap中取出相应的信息,调用者需要将其转化为正确的类
* @param key
* @return
* 【闫涛 2015.09.17】初始版本
*/
public static Object getObject(String key) {
return params.get(key);
}
public void exitApp() {
System.exit(1);
}
public static WkyApplication instance = null;
private static HashMap<String, Object> params = new HashMap<String, Object>();
下面我们来看注册登录的基类WkyRegisterLoginModel类的实现:
public class WkyRegisterLoginModel extends WkyModel {
protected WkyRegisterLoginModel() {
WkyApplication.putObject(WkyConstants.ROLE_ID, Integer.valueOf(WkyConstants.ROLE_JYS));
WkyApplication.putObject(WkyConstants.REGISTER_LOGIN_STATE, Integer.valueOf(STATE_LOGIN));
roleId = (Integer)WkyApplication.getObject(WkyConstants.ROLE_ID);
state = (Integer)WkyApplication.getObject(WkyConstants.REGISTER_LOGIN_STATE);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
public final static int STATE_REGISTER = 1;
public final static int STATE_LOGIN = 2;
public final static int STATE_FORGET_PWD = 3;
public final static int STATE_ACTIVATE = 4;
private int state = STATE_LOGIN;
private int roleId = WkyConstants.ROLE_JYS;
}
在上面的代码中,里面有两个属性比较重要,第一个state代表注册登录Activity所处的状态,一共有四种:注册、登录、忘记密码、激活,第二个属性roleId代表用户的角色,可以是基因师也可以是大众。需要注意的是,在构造函数中,这两个属性的值是存到中心信息仓库中的。
下面看具体应用WkgJys中,怎样定义具体的Model类JysRegisterLoginModel:
public class JysRegisterLoginModel extends WkyRegisterLoginModel {
protected JysRegisterLoginModel() {
super();
isShared = false;
}
}
在这里,由于没有特别的需要,没有定义新的属性,因此代码很简单。但是需要注意的是isShared = false,意味着在onDestroy方法中,这个实例将被移除,不会被共享。
好了,有了上述代码,Model体系就创建完成了。在下一节中,我们将讲到怎样实现MVC中的C,即Activity的实现方式。
华丽的分隔线
******************************************************************************************************************************************************************************
希望大家多支持,有大家的支持,我才能走得更远,谢谢!
银行账号:622202 0200 1078 56128 闫涛
我的支付宝:yt7589@hotmail.com