1、MVP框架担任角色
Model: 处理数据,包过网络请求、提交数据;缓存、读写本地数据、写入;写入、读取数据库数据等
View: 提供Activity需要实现方法,本身是一个接口,实际在Presenter中被调用执行。
Presenter: 业务处理,内部持有Model和View;使用CallBack获取Model获取结果信息。
Activity: 实现View提供方法,持有Presenter对象;在监听事件中调用Presenter方法,其他初始化与之前MVC一样。
2、使用优缺点
优点:
1、解耦:对于页面处理差异性、兼容性非常好;在于请求数据参数可能需要改变情况可以很好做到隔离性,在Model可以处理,不需要改变Activity流程。
2、分解:简化代码、将一个类中几百上千行都拆分处理,使得整个流程看起来更清晰。
缺点:
1、建立类多、容易造成内存泄漏,对于不熟悉Mvp上手有点难度、不好调试出现bug,不清楚执行方法流向。
总结:在对于单一功能、逻辑不复杂的页面并不建议使用MVP模式分解;所以最后看项目适用情况,哪个页面需要MVP分解,大多页面使用MVC即可。
3、实例
Demo结构
解耦
需求:对于不同地区app登录检车业务、其中各个地区以内网开发;登录参数可能由于不同地区有细微差异性。登录页面需要高度统一不变的前提下,使用MVP就是量身打造。
IView 接口
public interface IView {
void show();
void hide();
void toMainActivity();
void tip(String msg);
}
这个接口主要负责对于Activity一些形态,比如提示信息,显示进度条,调转其他页面等
LoginActivity 页面
public class LoginActivity extends AppCompatActivity implements IView,View.OnClickListener{
private IPresenter presenter;
private ProgressDialog progressDialog;
private EditText et_name;
private EditText et_password;
private Button btn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name=findViewById(R.id.username);
et_password=findViewById(R.id.password);
btn=findViewById(R.id.btn);
btn.setOnClickListener(this);
presenter=new IPresenter(this,new IMode());
progressDialog=new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在请求...");
}
@Override
public void show() {
progressDialog.show();
}
@Override
public void hide() {
progressDialog.hide();
}
@Override
public void toMainActivity() {
startActivity(new Intent(this, HomeActivity.class));
}
@Override
public void tip(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.detachView();
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn:
String name=et_name.getText().toString().trim();
String password=et_password.getText().toString().trim();
presenter.login(name,password);
break;
default:
break;
}
}
}
这个页面LoginActivit对于初始化控件及点击事件、获取控件数据操作依旧保留不变,对于实现view方法具体由Presenter调用。
IMode 处理数据
public class IMode {
/**
* 登录接口
* @param url
* @param map
* @param callback
*/
public void login(String url, Map map , StringCallback callback){
OkHttpManager.get(url,map).execute(callback);
}
/**
* 获取当前站点接口
*/
public void getNowWhere(String url,StringCallback callback){
OkHttpManager.get(url).execute(callback);
}
}
这个Imode处理数据,请求网络,结果StringCallBack回调,并且将结果返回到Presenter处理。上面使用的是鸿洋大神OKhttpUtils框架。
IPresenter 业务处理
public class IPresenter {
private IView view;
private IMode mode;
public IPresenter(IView view,IMode mode){
this.view=view;
this.mode=mode;
}
public void login(final String name, final String psw){
if(TextUtils.isEmpty(name)){
if(isViewAttached()){
view.tip("用戶名為空!");
}
return;
}
if(TextUtils.isEmpty(psw)){
if(isViewAttached()){
view.tip("密碼為空!");
}
return;
}
if(isViewAttached()){
view.show();
}
//延迟一秒,请求数据;显示进度条作用
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mode.getNowWhere(NetUrl.KEY_WHERE, new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
if(isViewAttached()){
view.hide();
view.tip("获取站点信息错误:"+e.getMessage());
}
}
@Override
public void onResponse(String response, int id) {
if(isViewAttached()){
view.hide();
}
String[] where={"A","B","C","D"};
int index=new Random().nextInt(4);
String now=where[index];
Log.e("QISHUI","当前登录站:"+now);
switch (now){
case "A":
loginA(name,psw);
break;
case "B":
loginB(name,psw);
break;
case "C":
loginC(name,psw);
break;
case "D":
loginD(name,psw);
break;
default:
break;
}
}
});
}
},1000);
}
/**
* A站点登录
*/
public void loginA(String name ,String password){
if(isViewAttached()){
view.show();
}
Map<String,String> map=new HashMap();
map.put("namea",name);
map.put("pwda",password);
mode.login(NetUrl.KEY_WHERENOW, map, new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
if(isViewAttached()){
view.hide();
view.tip("登录A信息错误:"+e.getMessage());
}
}
@Override
public void onResponse(String response, int id) {
if(isViewAttached()){
view.hide();
view.toMainActivity();
//其他处理
}
}
});
}
/**
* B站点登录
*/
public void loginB(String name ,String password){
if(isViewAttached()){
view.show();
}
Map<String,String> map=new HashMap();
map.put("nameb",name);
map.put("pwdb",password);
map.put("mac","1s:12:34:67:rt:13");
mode.login(NetUrl.KEY_WHERENOW, map, new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
if(isViewAttached()){
view.hide();
view.tip("登录B信息错误:"+e.getMessage());
}
}
@Override
public void onResponse(String response, int id) {
if(isViewAttached()){
view.hide();
view.toMainActivity();
//其他处理
}
}
});
}
/**
* C站点登录
*/
public void loginC(String name ,String password){
if(isViewAttached()){
view.show();
}
Map<String,String> map=new HashMap();
map.put("namec",name);
map.put("pwdc",password);
map.put("imei","123456789044444");
mode.login(NetUrl.KEY_WHERENOW, map, new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
if(isViewAttached()){
view.hide();
view.tip("登录C信息错误:"+e.getMessage());
}
}
@Override
public void onResponse(String response, int id) {
if(isViewAttached()){
view.hide();
view.toMainActivity();
//其他处理
}
}
});
}
/**
* D站点登录
*/
public void loginD(Strin