前言:
各位同學(xué)大家好 有段時間沒有給各位更新文章了重归, 具體多久我也不清楚 ,最近整理了一下andorid 開發(fā)中幾種常用的代碼架構(gòu)模式 (這里要跟java的設(shè)計模式區(qū)分開, 是代碼整體架構(gòu)不是 傳統(tǒng)java 23種設(shè)計模式)今天就寫了一個簡單例子分享給大家俘枫,那么廢話不多說 我們正式開始囱晴。
具體使用場景
效果圖
我們這邊在輸入框 輸入我們要查詢的賬號 然后點擊中間button 完成查詢 箱季,然后將結(jié)果顯示在屏幕上面的textview里面 (這里只是模式的查詢效果)然后分析其功能在不同架構(gòu)上面的實現(xiàn)方式
-
無框架
具體代碼實現(xiàn)(無框架)
package com.app.mvc_demo.normal;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.app.mvc_demo.R;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
import java.util.Random;
/***
*
*創(chuàng)建人:xuqing
* 類說明:無架構(gòu)實現(xiàn)
*
*
*/public class NormalActivity extends AppCompatActivity implements View.OnClickListener{
private EditText ed_account;
private TextView text_account;
private Button getacount_btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal);
initview();
}
private void initview() {
ed_account=findViewById(R.id.ed_account);
text_account=findViewById(R.id.account_text);
getacount_btn=findViewById(R.id.get_account_btn);
getacount_btn.setOnClickListener(this);
}
private String getUserInput(){
return ed_account.getText().toString().trim();
}
private void showSuccessPage(Account account){
text_account.setText("用戶賬號:"+account.getName()+"用戶等級"+account.getLevel());
}
private void showFailedPage(){
text_account.setText("獲取用戶數(shù)據(jù)失敗");
}
private void getAccountData(String accountName, Mcallback mcallback){
Random random=new Random();
boolean isSuccess=random.nextBoolean();
if(isSuccess){
Account account=new Account();
account.setLevel(100);
account.setName(accountName);
mcallback.onSuccess(account);
}else{
mcallback.onFailed();
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.get_account_btn:
String userInput=getUserInput();
getAccountData(userInput, new Mcallback() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFailed() {
showFailedPage();
}
});
}
}
}
我們觀察整個實現(xiàn)的代碼 裸删,我們可以看到為了實現(xiàn)上面的查詢賬戶的功能 在無架構(gòu)的情況下 我們把所有的邏輯代碼都寫在一個activity 里面 雖然功能可以實現(xiàn),但其負(fù)擔(dān)過重,代碼復(fù)查時繁瑣换帜,一旦需要修改楔壤,復(fù)雜項目極難維護(hù) ,所以一般實戰(zhàn)項目開發(fā)我們非常不推薦這種做法 除非你只是一個簡單的學(xué)習(xí)demo邏輯很少 可以簡單實現(xiàn)。
-
mvc架構(gòu)
在mvc 架構(gòu)里面我們把這個項目分成 model view controller 三層 model 是我們獲取數(shù)據(jù)的具體方法(mvcmodel )view就是我們的xml布局文件 controller 就是我們的activity fragment 等
具體代碼實現(xiàn)(mvc 架構(gòu))
activity 代碼
package com.app.mvc_demo.mvc;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.app.mvc_demo.R;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
public class MvcActivity extends AppCompatActivity implements View.OnClickListener{
private EditText ed_account;
private TextView text_account;
private Button getacount_btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal);
initview();
}
private void initview() {
ed_account=findViewById(R.id.ed_account);
text_account=findViewById(R.id.account_text);
getacount_btn=findViewById(R.id.get_account_btn);
getacount_btn.setOnClickListener(this);
}
private String getUserInput(){
return ed_account.getText().toString().trim();
}
private void showSuccessPage(Account account){
text_account.setText("用戶賬號:"+account.getName()+"用戶等級"+account.getLevel());
}
private void showFailedPage(){
text_account.setText("獲取用戶數(shù)據(jù)失敗");
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.get_account_btn:
String userInput=getUserInput();
MvcModel.getAccountData(userInput, new Mcallback() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFailed() {
showFailedPage();
}
});
}
}
}
mvc model
package com.app.mvc_demo.mvc;
import com.ap.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
import java.util.Random;
public class MvcModel {
public static void getAccountData(String accountName, Mcallback mcallback){
Random random=new Random();
boolean isSuccess=random.nextBoolean();
if(isSuccess){
Account account=new Account();
account.setLevel(100);
account.setName(accountName);
mcallback.onSuccess(account);
}else{
mcallback.onFailed();
}
}
}
我們看到在mvc 架構(gòu)模式下我們將獲取數(shù)據(jù)的邏輯 抽離到mvcModel 中實現(xiàn) 我們就會簡化掉 activity中的代碼邏輯 ,但是缺點仍然存在惯驼,在MVC框架下蹲嚣,雖然將獲取數(shù)據(jù)與界面展示分割開來,但對于Controller層祟牲,仍然擁有很多權(quán)利隙畜,隨著功能的增多,其代碼量也將會大大增長说贝,不利于維護(hù)修改议惰。
-
MVP架構(gòu)模式
在mvp架構(gòu)中 我們把整個項目代碼的邏輯分為 model view Presenter model model 是我們獲取數(shù)據(jù)的具體方法 (mvpmodel )view 是我們的xml文件 原來在mvc 中的controller 處理繁雜的邏輯我們都放到 Presenter 中進(jìn)行
具體代碼(MVP)
package com.app.mvc_demo.mvp;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.app.mvc_demo.R;
import com.app.mvc_demo.bean.Account;
public class MvpActivity extends AppCompatActivity implements View.OnClickListener,IMVPView {
private EditText ed_account;
private TextView text_account;
private Button getacount_btn;
private MVPPersenter mvpPersenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal);
initview();
mvpPersenter=new MVPPersenter(this);
}
private void initview() {
ed_account=findViewById(R.id.ed_account);
text_account=findViewById(R.id.account_text);
getacount_btn=findViewById(R.id.get_account_btn);
getacount_btn.setOnClickListener(this);
}
public String getUserInput(){
return ed_account.getText().toString().trim();
}
public void showSuccessPage(Account account){
text_account.setText("用戶賬號:"+account.getName()+"用戶等級"+account.getLevel());
}
public void showFailedPage(){
text_account.setText("獲取用戶數(shù)據(jù)失敗");
}
@Override
public void onClick(View v) {
String userInput=getUserInput();
mvpPersenter.getData(userInput);
}
}
mvpmodel
package com.app.mvc_demo.mvp;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
import java.util.Random;
public class MVPModel {
public void getAccountData(String accountName, Mcallback mcallback){
Random random=new Random();
boolean isSuccess=random.nextBoolean();
if(isSuccess){
Account account=new Account();
account.setLevel(100);
account.setName(accountName);
mcallback.onSuccess(account);
}else{
mcallback.onFailed();
}
}
}
IMVPView
IMvpview
package com.app.mvc_demo.mvp;
import com.app.mvc_demo.bean.Account;
public interface IMVPView {
String getUserInput();
void showSuccessPage(Account account);
void showFailedPage();
}
MVPPersenter
package com.app.mvc_demo.mvp;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
public class MVPPersenter {
private IMVPView imvpView;
private MVPModel mvpModel;
public MVPPersenter(IMVPView imvpView) {
this.imvpView = imvpView;
mvpModel=new MVPModel();
}
public void getData(String accountName){
mvpModel.getAccountData(accountName, new Mcallback() {
@Override
public void onSuccess(Account account) {
imvpView.showSuccessPage(account);
}
@Override
public void onFailed() {
imvpView.showFailedPage();
}
});
}
}
在mvp架構(gòu)中 我們發(fā)現(xiàn)我們會在activtiy 直接操作那些邏輯 而是在MVPPersenter 中持有mvpmodel的引用然后在 MVPPersenter 的構(gòu)造方法中傳入 IMVPView的對象 我們在mvpModel 的回調(diào)方法里面在用imvpView 講拿到的數(shù)據(jù)結(jié)果回調(diào)到activity 或者fragment 中,然后我們在activity 或者fragment中實現(xiàn)imvpvidew中方法即可獲取數(shù)據(jù)結(jié)果
在使用MVP框架時乡恕,View層與Model層不通信言询,都通過 Presenter層傳遞,并且Presenter層與具體的View是沒有直接關(guān)聯(lián)的傲宜,而是通過定義好的接口進(jìn)行交互运杭,這就可能會導(dǎo)致有大量的接口生成,代碼復(fù)雜繁瑣蛋哭,難維護(hù)县习。
- 1 因此涮母,在使用MVP時最好按照一定規(guī)范去做:
- 2 接口規(guī)范化(封裝父類接口以減少接口的使用量)
- 3使用第三方插件自動生成MVP代碼
- 4 對于一些簡單的界面谆趾,可以選擇不使用框架
- 5根據(jù)項目復(fù)雜程度,部分模塊可以選擇不使用接口
MVVM架構(gòu)
在mvvm 架構(gòu)中 我們將整個項目分為 model view viewmodel model model 是我們獲取數(shù)據(jù)的具體方法 (mvpmodel ) view 是我們的xml文件 viewmodel 處理業(yè)務(wù)邏輯數(shù)據(jù)更新 MVVM框架實現(xiàn)了數(shù)據(jù)與視圖的綁定(DataBinding)叛本,當(dāng)數(shù)據(jù)變化時沪蓬,視圖會自動更新;反之来候,當(dāng)視圖變化時跷叉,數(shù)據(jù)會自動更新。
我們要使用mvvm 首先我們要學(xué)會使用 DataBinding
DataBinding 使用步驟
- 1啟用DataBinding
- 2修改布局文件為DataBinding布局
- 3數(shù)據(jù)綁定
啟用DataBinding
在build.gradle里面添加依賴代碼配置開啟 databinding支持
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
修改布局文件為DataBinding布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.app.mvc_demo.mvvm.MVVMViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".normal.NormalActivity">
<EditText
android:id="@+id/ed_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:hint="請輸入要查詢的賬號">
</EditText>
<Button
android:id="@+id/get_account_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="獲取賬號信息"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:onClick="@{viewModel.getData}"
>
</Button>
<TextView
android:id="@+id/account_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="80dp"
android:text="@{viewModel.result}"
android:hint="賬號信息未獲取"
>
</TextView>
</LinearLayout>
</layout>
我們在布局文件中鼠標(biāo)放在最外層布局 然后按住alt+enter 鍵就可以修改為databinding布局
MVVM框架使用步驟:
- 1提供View、ViewModel以及Model三層
- 2 將布局修改為DataBinding布局
- 3View與ViewMedel之間通過DataBinding進(jìn)行通信
- 4獲取數(shù)據(jù)并展示在界面上
再更深層次學(xué)習(xí)云挟,可以使用LiveData+ViewModel
具體代碼實現(xiàn)(mvvm )
mvvmactivity
package com.app.mvc_demo.mvvm;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import com.app.mvc_demo.R;
import com.app.mvc_demo.databinding.ActivityMvvmBinding;
/***
*
* 創(chuàng)建人:xuqing
* 類說明:mvvmactivity
*
*
*/
public class MVVMActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMvvmBinding binding= DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
MVVMViewModel mvvmViewModel=new MVVMViewModel(getApplication(),binding);
binding.setViewModel(mvvmViewModel);
}
}
修改布局setContentView 為
ActivityMvvmBinding binding= DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
實例化mvvmmodel 并且set到databinding上面
MVVMViewModel mvvmViewModel=new MVVMViewModel(getApplication(),binding);
binding.setViewModel(mvvmViewModel);
MVVMModel
package com.app.mvc_demo.mvvm;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
import java.util.Random;
public class MVVMModel {
public void getAccountData(String accountName, Mcallback mcallback){
Random random=new Random();
boolean isSuccess=random.nextBoolean();
if(isSuccess){
Account account=new Account();
account.setLevel(100);
account.setName(accountName);
mcallback.onSuccess(account);
}else{
mcallback.onFailed();
}
}
}
xml 布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.app.mvc_demo.mvvm.MVVMViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".normal.NormalActivity">
<EditText
android:id="@+id/ed_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:hint="請輸入要查詢的賬號">
</EditText>
<Button
android:id="@+id/get_account_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="獲取賬號信息"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:onClick="@{viewModel.getData}"
>
</Button>
<TextView
android:id="@+id/account_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="80dp"
android:text="@{viewModel.result}"
android:hint="賬號信息未獲取"
>
</TextView>
</LinearLayout>
</layout>
MVVMViewModel
package com.app.mvc_demo.mvvm;
import android.app.Application;
import android.util.Log;
import android.view.View;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import com.app.mvc_demo.bean.Account;
import com.app.mvc_demo.callback.Mcallback;
import com.app.mvc_demo.databinding.ActivityMvvmBinding;
public class MVVMViewModel extends BaseObservable {
private static final String TAG = "MVVMViewModel";
private MVVMModel mvvmModel;
private ActivityMvvmBinding binding;
private String result;
public MVVMViewModel(Application application,ActivityMvvmBinding binding){
mvvmModel=new MVVMModel();
this.binding=binding;
}
public void getData(View view){
String userInput = binding.edAccount.getText().toString();
mvvmModel.getAccountData(userInput, new Mcallback() {
@Override
public void onSuccess(Account account) {
String info=account.getName()+"+|"+account.getLevel();
Log.e(TAG, "onSuccess: info "+info );
setResult(info);
}
@Override
public void onFailed() {
setResult("獲取數(shù)據(jù)失敗");
}
});
}
@Bindable
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
notifyPropertyChanged(com.app.mvc_demo.BR.result);
}
}
我們可以看到在使用了databinding布局之后 我們可以直接就在xml文件 view 調(diào)用viewmodel里面的方法 然后我們在viewmodel中持有mvvmmodel的引用 我們實現(xiàn)了mvvmmodel中方法 然后我們通過
notifyPropertyChanged 來刷新xml文件 view 中顯示效果.
使用了mvvm框架+上databinding可以·直接view調(diào)用viewmodel中的方法 大大簡化了我們activity的邏輯代碼 但是有些必須在activity中實現(xiàn)的代碼 例如申請權(quán)限之類我們可以通過 可以使用LiveData+ViewModel 去處理這個同學(xué)們可以自己去研究 我這邊就不張開講了
最后總結(jié)
在安卓開發(fā)中我們應(yīng)該都有接觸到這三方代碼架構(gòu)模式 個人覺得具體用那種代碼架構(gòu)看項目 個開發(fā)項目組 我是做游戲SDK開發(fā) 就一個 所以我個人在開發(fā)中 首選mvc 應(yīng)為mvvm要引入很多三方庫不友好 mvp要封裝很多接口 項目本身邏輯少 所以我也不去用 要是開發(fā)app同學(xué)可以優(yōu)先使用mvvm或者mvp 在代碼整個解耦方面和后期維護(hù) 要比mvc要友好很多,最后希望我的文章能幫助到各位解決問題 梆砸,以后我還會貢獻(xiàn)更多有用的代碼分享給大家。各位同學(xué)如果覺得文章還不錯 园欣,麻煩給關(guān)注和star帖世,小弟在這里謝過啦!