美文网首页
Android 设计架构

Android 设计架构

作者: 帅气Name | 来源:发表于2017-04-24 14:17 被阅读64次

    1、MVP架构

    直接上图:

    mvp
    • Model层
      • Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合)
    • View层
      • View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity)
    • Presenter层
      • Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑

    Android SDK

    当我们简要分析Android SDK之后,尤其是layout和activity之间的关系,能很强烈的感觉到最适合Android的设计模式是MVC。但是随着项目复杂性的增加,MVC对于一些功能点的分离支持的不是特别好,尤其是单元测试。

    现在,Android SDK开始逐渐允许我们使用其他类型的架构模式,甚至是没有任何架构模式,反模式。

    MVC、MVP的区别

    MVC定义:

    Model–view–controller (MVC)主要是(但不限于)用于在计算机上实现用户界面的软件架构设计模式。它把一个既定的软件应用程序分为三个相互连接的部分,以便于把显示内容或者从用户获取信息的这两种内在的数据表现动作分离出来。

    MVP定义

    Model–view–presenter (MVP)是MVC设计模式的推导,并主要用于构建用户界面。在MVP中Presenter承担了“中间人”的功能,并且所有的表示逻辑都交给了Presenter。主要作用是功能点分离。

    mvp与mvc的区别

    两种模式的主要区别:

    • (最主要区别)View与Model并不直接交互,而是通过与Presenter交互来与Model间接交互。而在MVC中View可以与Model直接交互

    • 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。而Controller是基于行为的,并且可以被多个View共享,Controller可以负责决定显示哪个View

    • Presenter与View的交互是通过接口来进行的,更有利于添加单元测试。


    代码上的区别:

    MVC -- View&Controller

    
        public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener {
    
            private WeatherModel weatherModel;
            private EditText cityNOInput;
            private TextView city;
            ...
    
            //activity启动时调用的
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
    
                //加载xml文件,view
                setContentView(R.layout.activity_main);
                initView();
    
                //获取weatherModel实例,model
                weatherModel = new WeatherModelImpl();
            }
    
            //初始化View
            private void initView() {
                cityNOInput = findView(R.id.et_city_no);
                city = findView(R.id.tv_city);
                ...
                findView(R.id.btn_go).setOnClickListener(this);
            }
    
            //显示结果
            public void displayResult(Weather weather) {
                WeatherInfo weatherInfo = weather.getWeatherinfo();
                city.setText(weatherInfo.getCity());
                ...
            }
    
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                    case R.id.btn_go:
                        weatherModel.getWeather(cityNOInput.getText().toString().trim(), this);
                        break;
                }
            }
    
            @Override
            public void onSuccess(Weather weather) {
                displayResult(weather);
            }
    
            @Override
            public void onError() {
                Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();
            }
    
            private T findView(int id) {
                return (T) findViewById(id);
            }
        }
    
    

    MVC -- Model

    
        //接口
        public interface WeatherModel {
            void getWeather(String cityNumber, OnWeatherListener listener);
        }
    
        -----
    
        public class WeatherModelImpl implements WeatherModel{
    
            @Override
            public void getWeather(String cityNumber, final OnWeatherListener listener) {
    
                /*数据层操作*/
                VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html,
                        Weather.class, new Response.Listener<weather>() {
                            @Override
                            public void onResponse(Weather weather) {
                                if (weather != null) {
                                    listener.onSuccess(weather);
                                } else {
                                    listener.onError();
                                }
                            }
                        }, new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError error) {
                                listener.onError();
                            }
                        });
            }
        }
    
    

    缺点:

    在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户 界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。



    MVP -- Model

    
        //bean类
        public class UserBean {
             private String mFirstName;
             private String mLastName;
             public UserBean(String firstName, String lastName) {
                    this. mFirstName = firstName;
                    this. mLastName = lastName;
             }
             public String getFirstName() {
                    return mFirstName;
             }
             public String getLastName() {
                    return mLastName;
             }
        }
    
        ----
    
        //Model的接口
        public interface IUserModel {
    
             void setID(int id);
    
             void setFirstName(String firstName);
    
             void setLastName(String lastName);
    
             int getID();
    
             UserBean load(int id);// 通过id读取user信息,返回一个UserBean
        }
    
    

    MVP -- View

    
        public interface IUserView {
             int getID();
    
             String getFristName();
    
             String getLastName();
    
             void setFirstName(String firstName);
    
             void setLastName(String lastName);
        }
    
        -----
    
        public class MainActivity extends Activity implements OnClickListener,IUserView {
    
             UserPresenter presenter;
             EditText id,first,last;
             @Override
             protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                   setContentView(R.layout. activity_main);
    
                   findViewById(R.id. save).setOnClickListener( this);
                   findViewById(R.id. load).setOnClickListener( this);
                    id = (EditText) findViewById(R.id. id);
                    first = (EditText) findViewById(R.id. first);
                    last = (EditText) findViewById(R.id. last);
    
                    presenter = new UserPresenter( this);
             }
    
             @Override
             public void onClick(View v) {
                    switch (v.getId()) {
                    case R.id. save:
                         presenter.saveUser(getID(), getFristName(), getLastName());
                         break;
                    case R.id. load:
                         presenter.loadUser(getID());
                         break;
                    default:
                         break;
                   }
             }
    
             @Override
             public int getID() {
                    return new Integer( id.getText().toString());
             }
    
             @Override
             public String getFristName() {
                    return first.getText().toString();
             }
    
             @Override
             public String getLastName() {
                    return last.getText().toString();
             }
    
             @Override
             public void setFirstName(String firstName) {
                    first.setText(firstName);
             }
    
             @Override
             public void setLastName(String lastName) {
                    last.setText(lastName);
             }
    
        }
    
    

    MVP的优势:

    • Activity的代码不臃肿;
    • Model的改动不会影响Activity(View),两者也互不干涉,而在MVC中会;
    • IUserView这个接口可以实现方便地对Presenter的测试;
    • UserPresenter可以用于多个视图,但是在MVC中的Activity就不行。

    MVP的缺点和一些解决方案:

    • 转移逻辑操作之后可能部分较为复杂的Activity内代码量还是不少。

    1、具体做法是在Activity内部分层。其中最顶层为BaseActivity,不做具体显示,而是提供一些基础样式,Dialog,ActionBar在内的内容,展现给用户的Activity继承BaseActivity,重写BaseActivity预留的方法。
    2、使用fragment分层。能用fragment独立区分的布局,尽量用fragment分开。

    • 模型层(Model)中的整体代码量是最大的,一般由大量的Package组成。

    针对这部分需要做的就是在程序设计的过程中,做好模块的划分,进行接口隔离,在内部进行分层。

    • 强化Presenter的作用,将所有逻辑操作都放在Presenter内也容易造成代码量过大。

    在UI层和Presenter之间设置中介者Mediator,将例如数据校验、组装在内的轻量级逻辑操作放在Mediator中;在Presenter和Model之间使用代理Proxy;通过上述两者分担一部分Presenter的逻辑操作,但整体框架的控制权还是在Presenter手中。Mediator和Proxy不是必须的,只在Presenter负担过大时才建议使用。

    终极mvp

    2、MVVM架构

    什么是MVVM

    MVVMMVVM

    是不是和MVP很像,只是把Presenter改成了ViewModel。

    但是!!!

    这里的“Model”指的是View的Model,跟MVP中的一个Model不是一回事。所谓View的Model就是包含View的一些数据属性和操作的这么一个东西,这种模式的关键技术就是数据绑定(data binding),View的变化会直接影响ViewModel,ViewModel的变化或者内容也会直接体现在View上。这种模式实际上是框架替应用开发者做了一些工作,开发者只需要较少的代码就能实现比较复杂的交互。

    在我理解的MVVM是MVP的进一步升级。Data Binding框架将会接管Presenter的主要职责(作用于model和view上),Presenter的其他剩余职责(从仓库中获取数据并进行格式化处理)则由ViewModel(一个增强版的Model)接管。ViewModel是一个独立的Java类,它的唯一职责是表示一个View后面的数据。它可以合并来自多个数据源(Models)的数据,并将这些数据加工后用于展示。


    代码展示

    MVP - VIEW - XML

    
       <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            android:paddingBottom="@dimen/activity_vertical_margin"
            tools:context=".MainActivityFragment">
    
            <TextView
                android:text="..."
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:id="@+id/loggedInUserCount"/>
    
            <TextView
                android:text="# logged in users:"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="false"
                android:layout_toLeftOf="@+id/loggedInUserCount"/>
    
            <RadioGroup
                android:layout_marginTop="40dp"
                android:id="@+id/existingOrNewUser"
                android:gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:orientation="horizontal">
    
                <RadioButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Returning user"
                    android:id="@+id/returningUserRb"/>
    
                <RadioButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="New user"
                    android:id="@+id/newUserRb"
                    />
    
            </RadioGroup>
    
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/username_block"
                android:layout_below="@+id/existingOrNewUser">
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:text="Username:"
                    android:id="@+id/textView"
                    android:minWidth="100dp"/>
    
                <EditText
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/username"
                    android:minWidth="200dp"/>
            </LinearLayout>
    
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentStart="false"
                android:id="@+id/password_block"
                android:layout_below="@+id/username_block">
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:text="Password:"
                    android:minWidth="100dp"/>
    
                <EditText
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:inputType="textPassword"
                    android:ems="10"
                    android:id="@+id/password"/>
    
            </LinearLayout>
    
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/password_block"
                android:id="@+id/email_block">
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:text="Email:"
                    android:minWidth="100dp"/>
    
                <EditText
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:inputType="textEmailAddress"
                    android:ems="10"
                    android:id="@+id/email"/>
            </LinearLayout>
    
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Log in"
                android:id="@+id/loginOrCreateButton"
                android:layout_below="@+id/email_block"
                android:layout_centerHorizontal="true"/>
        </RelativeLayout> 
    
    

    MVP - VIEW - JAVA

    
        public class MainActivityFragment extends MvpFragment implements MvpView {
            @InjectView(R.id.username)
            TextView mUsername;
    
            @InjectView(R.id.password)
            TextView mPassword;
    
            @InjectView(R.id.newUserRb)
            RadioButton mNewUserRb;
    
            @InjectView(R.id.returningUserRb)
            RadioButton mReturningUserRb;
    
            @InjectView(R.id.loginOrCreateButton)
            Button mLoginOrCreateButton;
    
            @InjectView(R.id.email_block)
            ViewGroup mEmailBlock;
    
            @InjectView(R.id.loggedInUserCount)
            TextView mLoggedInUserCount;
    
            public MainActivityFragment() {
            }
    
            @Override
            public MainPresenter createPresenter() {
                return new MainPresenter();
            }
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                return inflater.inflate(R.layout.fragment_main, container, false);
            }
    
            @Override
            public void onViewCreated(View view, Bundle savedInstanceState) {
                super.onViewCreated(view, savedInstanceState);
                attachEventListeners();
            }
    
            private void attachEventListeners() {
                mNewUserRb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        updateDependentViews();
                    }
                });
                mReturningUserRb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        updateDependentViews();
                    }
                });
            }
    
            /** Prepares the initial state of the view upon startup */
            public void setInitialState() {
                mReturningUserRb.setChecked(true);
                updateDependentViews();
            }
    
            /** Shows/hides email field and sets correct text of login button depending on state of radio buttons */
            public void updateDependentViews() {
                if (mReturningUserRb.isChecked()) {
                    mEmailBlock.setVisibility(View.GONE);
                    mLoginOrCreateButton.setText(R.string.log_in);
                }
                else {
                    mEmailBlock.setVisibility(View.VISIBLE);
                    mLoginOrCreateButton.setText(R.string.create_user);
                }
            }
    
            public void setNumberOfLoggedIn(int numberOfLoggedIn) {
                mLoggedInUserCount.setText(""  + numberOfLoggedIn);
            }
    
            @OnClick(R.id.loginOrCreateButton)
            public void loginOrCreate() {
                if (mNewUserRb.isChecked()) {
                    Toast.makeText(getActivity(), "Please enter a valid email address", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getActivity(), "Invalid username or password", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
    ``
    
    MVP – PRESENTER
    
    ```java
    
        public class MainPresenter implements MvpPresenter {
            MainModel mModel;
            private MainActivityFragment mView;
    
            public MainPresenter() {
                mModel = new MainModel();
            }
    
            @Override
            public void attachView(MainActivityFragment view) {
                mView = view;
                view.setInitialState();
                updateViewFromModel();
                ensureModelDataIsLoaded();
            }
    
            @Override
            public void detachView(boolean retainInstance) {
                mView = null;
            }
    
            private void ensureModelDataIsLoaded() {
                if (!mModel.isLoaded()) {
                    mModel.loadAsync(new Handler.Callback() {
                        @Override
                        public boolean handleMessage(Message msg) {
                            updateViewFromModel();
                            return true;
                        }
                    });
                }
            }
    
            /** Notifies the views of the current value of "numberOfUsersLoggedIn", if any */
            private void updateViewFromModel() {
                if (mView != null && mModel.isLoaded()) {
                    mView.setNumberOfLoggedIn(mModel.numberOfUsersLoggedIn);
                }
            }
        }
    
    

    MVP – MODEL

    
        public class MainModel {
            public Integer numberOfUsersLoggedIn;
            private boolean mIsLoaded;
            public boolean isLoaded() {
                return mIsLoaded;
            }
    
            public void loadAsync(final Handler.Callback onDoneCallback) {
                new AsyncTask() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        // Simulating some asynchronous task fetching data from a remote server
                        try {Thread.sleep(2000);} catch (Exception ex) {};
                        numberOfUsersLoggedIn = new Random().nextInt(1000);
                        mIsLoaded = true;
                        return null;
                    }
    
                    @Override
                    protected void onPostExecute(Void aVoid) {
                        onDoneCallback.handleMessage(null);
                    }
                }.execute((Void) null);
            }
        }
    
    


    MVVM – VIEW – XML

    
        <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
            <data>
                <variable name="data" type="com.nilzor.presenterexample.MainModel"/>
            </data>
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".MainActivityFragment">
    
                <TextView
                    android:text="@{data.numberOfUsersLoggedIn}"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="true"
                    android:id="@+id/loggedInUserCount"/>
    
                <TextView
                    android:text="# logged in users:"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="false"
                    android:layout_toLeftOf="@+id/loggedInUserCount"/>
    
                <RadioGroup
                    android:layout_marginTop="40dp"
                    android:id="@+id/existingOrNewUser"
                    android:gravity="center"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerHorizontal="true"
                    android:orientation="horizontal">
    
                    <RadioButton
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Returning user"
                        android:checked="@{data.isExistingUserChecked}"
                        android:id="@+id/returningUserRb"/>
    
                    <RadioButton
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="New user"
                        android:id="@+id/newUserRb"
                        />
    
                </RadioGroup>
    
                <LinearLayout
                    android:orientation="horizontal"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:id="@+id/username_block"
                    android:layout_below="@+id/existingOrNewUser">
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:text="Username:"
                        android:id="@+id/textView"
                        android:minWidth="100dp"/>
    
                    <EditText
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:id="@+id/username"
                        android:minWidth="200dp"/>
                </LinearLayout>
    
                <LinearLayout
                    android:orientation="horizontal"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentStart="false"
                    android:id="@+id/password_block"
                    android:layout_below="@+id/username_block">
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:text="Password:"
                        android:minWidth="100dp"/>
    
                    <EditText
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:inputType="textPassword"
                        android:ems="10"
                        android:id="@+id/password"/>
    
                </LinearLayout>
    
                <LinearLayout
                    android:orientation="horizontal"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/password_block"
                    android:id="@+id/email_block"
                    android:visibility="@{data.emailBlockVisibility}">
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:text="Email:"
                        android:minWidth="100dp"/>
    
                    <EditText
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:inputType="textEmailAddress"
                        android:ems="10"
                        android:id="@+id/email"/>
                </LinearLayout>
    
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{data.loginOrCreateButtonText}"
                    android:id="@+id/loginOrCreateButton"
                    android:layout_below="@+id/email_block"
                    android:layout_centerHorizontal="true"/>
            </RelativeLayout>
        </layout>
    
    

    MVVM – VIEW – JAVA

    
        public class MainActivityFragment extends Fragment {
            private FragmentMainBinding mBinding;
            private MainModel mViewModel;
    
            public MainActivityFragment() {
            }
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View view = inflater.inflate(R.layout.fragment_main, container, false);
                mBinding = FragmentMainBinding.bind(view);
                mViewModel = new MainModel(this, getResources());
                mBinding.setData(mViewModel);
                attachButtonListener();
                return view;
            }
    
            private void attachButtonListener() {
                mBinding.loginOrCreateButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mViewModel.logInClicked();
                    }
                });
            }
    
            @Override
            public void onViewCreated(View view, Bundle savedInstanceState) {
                ensureModelDataIsLodaded();
            }
    
            private void ensureModelDataIsLodaded() {
                if (!mViewModel.isLoaded()) {
                    mViewModel.loadAsync();
                }
            }
    
            public void showShortToast(String text) {
                Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
            }
        }
    
    
    
        public class MainModel {
            public ObservableField numberOfUsersLoggedIn = new ObservableField();
            public ObservableField isExistingUserChecked = new ObservableField();
            public ObservableField emailBlockVisibility = new ObservableField();
            public ObservableField loginOrCreateButtonText = new ObservableField();
            private boolean mIsLoaded;
            private MainActivityFragment mView;
            private Resources mResources;
    
            public MainModel(MainActivityFragment view, Resources resources) {
                mView = view;
                mResources = resources; // You might want to abstract this for testability
                setInitialState();
                updateDependentViews();
                hookUpDependencies();
            }
            public boolean isLoaded() {
                return mIsLoaded;
            }
    
            private void setInitialState() {
                numberOfUsersLoggedIn.set("...");
                isExistingUserChecked.set(true);
            }
    
            private void hookUpDependencies() {
                isExistingUserChecked.addOnPropertyChangedCallback(new android.databinding.Observable.OnPropertyChangedCallback() {
                    @Override
                    public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
                        updateDependentViews();
                    }
                });
            }
    
            public void updateDependentViews() {
                if (isExistingUserChecked.get()) {
                    emailBlockVisibility.set(View.GONE);
                    loginOrCreateButtonText.set(mResources.getString(R.string.log_in));
                }
                else {
                    emailBlockVisibility.set(View.VISIBLE);
                    loginOrCreateButtonText.set(mResources.getString(R.string.create_user));
                }
            }
    
            public void loadAsync() {
                new AsyncTask() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        // Simulating some asynchronous task fetching data from a remote server
                        try {Thread.sleep(2000);} catch (Exception ex) {};
                        numberOfUsersLoggedIn.set("" + new Random().nextInt(1000));
                        mIsLoaded = true;
                        return null;
                    }
                }.execute((Void) null);
            }
    
            public void logInClicked() {
                // Illustrating the need for calling back to the view though testable interfaces.
                if (isExistingUserChecked.get()) {
                    mView.showShortToast("Invalid username or password");
                }
                else {
                    mView.showShortToast("Please enter a valid email address");
                }
            }
        }
    
    

    MVVM的优势:

    • 与MVP相比,减少了代码量。能更注重业务逻辑处理。

    可参考的项目:

    基于MVVM架构的Android项目

    总结:

    先实现,再重构!!!

    相关文章

      网友评论

          本文标题:Android 设计架构

          本文链接:https://www.haomeiwen.com/subject/vvhpzttx.html