今天学习开发框架MVP,对比于MVC ,
优点:activity,fragment,代码变得简洁优美,不像在MVC中,一个activity,fragment少则300,500行,多则几千行代码,便于后期维护。view层不再直接和model接触了,相应的逻辑(比如网络请求,数据运算)都交给 presenter,model层来做,view只负责界面绘制。方便写单元测试。
缺点:从MVC转至MVP学习有一定成本,对于小型项目,完全没有这个必要,MVC就足够了。举个简单例子,如果要编写一个演示dmeo从assets文件中取数据并显示出来,这样的需求,在MVC中1~2个java文件(很多时候activity扮演的是V、C)就搞定了,MVP却需要3个文件。
下面直接上代码吧
这是我的工程目录V层将通过 activity和 fragment两个来展示,下面分别介绍
public class CalculateTwoNumbers { public int n1, n2; public int addResult() { return n1 + n2; } public int subtractResult() { return n1 - n2; } public int multiplyResult() { return n1 * n2; } public double divideResult() { return n1 / n2; } }这是一个计算四则运算的model,这里我没有用到 set/get 方法,是因为性能的原因(某大神建议在有内联的场景下android中直接访问变量比通过set/get方法访问变量效率高些)。这样的代码结构很容易编写测试用例的,代码如下:
public class CalculateTwoNumbersTest extends TestCase { CalculateTwoNumbers calculateTwoNumbers = new CalculateTwoNumbers(); public void testAddResult() throws Exception { calculateTwoNumbers.n1 = 4; calculateTwoNumbers.n2 = 8; assertEquals(12,calculateTwoNumbers.addResult()); } public void testSubtractResult() throws Exception { calculateTwoNumbers.n1 = 4; calculateTwoNumbers.n2 = 8; assertEquals(-4,calculateTwoNumbers.subtractResult()); } public void testMultiplyResult() throws Exception { calculateTwoNumbers.n1 = 4; calculateTwoNumbers.n2 = 8; assertEquals(32,calculateTwoNumbers.multiplyResult()); } public void testDivideResult() throws Exception { calculateTwoNumbers.n1 = 14; calculateTwoNumbers.n2 = 8; assertEquals(1.0,calculateTwoNumbers.divideResult()); } }说完了model层,接着我们看看presenter层代码
public interface ICalculate { void mathAdd(int n1, int n2); void mathSubtract(int n1, int n2); void mathMultiply(int n1, int n2); void mathDivide(int n1, int n2); void clear(); }
public class CalculatePresenter implements ICalculate { private IResult iResult; private CalculateTwoNumbers calculateTwoNumbers; public CalculatePresenter(IResult iResult) { this.iResult = iResult; calculateTwoNumbers = new CalculateTwoNumbers(); } public void initUser(int n1, int n2) { calculateTwoNumbers.n1 = n1; calculateTwoNumbers.n2 = n2; mathAdd(n1, n2); mathSubtract(n1, n2); mathMultiply(n1, n2); mathDivide(n1, n2); } @Override public void mathAdd(int n1, int n2) { if (iResult != null) { iResult.showAdd(calculateTwoNumbers.addResult()); } } @Override public void mathSubtract(int n1, int n2) { if (iResult != null) { iResult.showSubtract(calculateTwoNumbers.subtractResult()); } } @Override public void mathMultiply(int n1, int n2) { if (iResult != null) { iResult.showMultiply(calculateTwoNumbers.multiplyResult()); } } @Override public void mathDivide(int n1, int n2) { if (iResult != null) { iResult.showDivide(calculateTwoNumbers.divideResult()); } } @Override public void clear() { if (iResult != null) { iResult = null; } } }CalculatePresenter负责将model运算的结果传递给view层,即本工程中的 MVPActivity,MVPFragment。
在activity和fragment中显示数据
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mvp_view_result); ButterKnife.bind(this); calculatePresenter = new CalculatePresenter(this); } @OnClick({R.id.btn_calculate}) void calculate() { if (TextUtils.isEmpty(etNumber1.getText().toString().trim()) || TextUtils.isEmpty(etNumber2.getText().toString().trim())) { showToastShort("please input numbers"); return; } if (calculatePresenter != null) { calculatePresenter.initUser(Integer.valueOf(etNumber1.getText().toString().trim()), Integer.valueOf(etNumber2.getText().toString().trim())); } } @Override protected void onDestroy() { calculatePresenter.clear(); ButterKnife.unbind(this); super.onDestroy(); } @Override public void showAdd(int result) { LogUtils.d("add: " + result); showToastShort("add: " + result); tvAdd.setText("add: " + result); } @Override public void showSubtract(int result) { LogUtils.d("subtract: " + result); showToastShort("subtract: " + result); tvSubtract.setText("subtract: " + result); } @Override public void showMultiply(int result) { LogUtils.d("multiply: " + result); showToastShort("multiply: " + result); tvMultiply.setText("multiply: " + result); } @Override public void showDivide(double result) { LogUtils.d("divide: " + result); showToastShort("divide: " + result); tvDivide.setText("divide: " + result); }这里要注意的是在activity中调用CalculatePresenter clear()方法解除绑定,和fragment中调用该方法解除绑定时有点小区别,MVPFragment中因为存在绑定的按钮点击事件,在销毁fragment时要解除绑定的 点击事件,不然会造成内存泄漏。
完整代码地址