今天學習開發框架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時要解除綁定的 點擊事件,不然會造成內存泄漏。
完整代碼地址