zoukankan      html  css  js  c++  java
  • MVP应用在android app上

          使用MVP模式来解耦activity中业务代码和界面代码。在activity中,将其中的业务抽象到presenter层;将其中的界面代码抽象到View层。

          

          MVP模式:

          

            一个软件被划分成三层,View层,Presenter层,Model层。

            View层的职责是展示界面,界面绘制。

            Presenter层的职责是,实现各种业务逻辑,业务逻辑的代码都放在这一层。

            Model层的职责是数据的存储,修改,获取。

            各层之间的交互:

            View层和Presenter层之间的通信是双向的。

            Presenter层和Model层之间的通信是双向的。

            View层不与Model层发生交互。

           

           MVP模式应用到Android app:

           View层:activity,fragment,其中的界面展示,就是View层的内容。

           Presenter层:点击一个按钮要执行的业务逻辑,则是由Presenter层来实现。也就是说,Presenter层抽象,提取出activity,fragment中的业务逻辑。这样就可以将业务逻辑代码与界面展示代码解耦掉。可以重用业务逻辑。

          Model层:这一层,则是数据存取,数据修改层。配置信息,获取数据源的数据,获取服务器数据,获取数据库的数据,更新数据库的数据,这些实现代码都由这一层来提供。

         MVP模式应用到Android app的一个例子分析:  

    例子分析:
     
    1.每个层要做的事情,用接口声明好。
    2.接口声明好之后,就用实际的类来实现。
     
    比如登陆界面:
    1.要确定出登陆界面,它的View有哪些行为。
    2.登陆界面的业务逻辑实现,是通过调用presenter层的方法来进行的。
    3.presenter与view之间是相互通信的。
     

    Login这个模块,把View层和presenter层放在了一起:

    package com.antonioleiva.mvpexample.app.Login;

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.ProgressBar;

    import com.antonioleiva.mvpexample.app.R;
    import com.antonioleiva.mvpexample.app.main.MainActivity;

    public class LoginActivity extends Activity implements LoginView, View.OnClickListener {

        private ProgressBar progressBar;
        private EditText username;
        private EditText password;
        private LoginPresenter presenter;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);

            progressBar = (ProgressBar) findViewById(R.id.progress);
            username = (EditText) findViewById(R.id.username);
            password = (EditText) findViewById(R.id.password);
            findViewById(R.id.button).setOnClickListener(this);

            presenter = new LoginPresenterImpl(this);
        }

        @Override public void showProgress() {
            progressBar.setVisibility(View.VISIBLE);
        }

        @Override public void hideProgress() {
            progressBar.setVisibility(View.GONE);
        }

        @Override public void setUsernameError() {
            username.setError(getString(R.string.username_error));
        }

        @Override public void setPasswordError() {
            password.setError(getString(R.string.password_error));
        }

        @Override public void navigateToHome() {
            startActivity(new Intent(this, MainActivity.class));
            finish();
        }

        @Override public void onClick(View v) {
            presenter.validateCredentials(username.getText().toString(), password.getText().toString());
        }

    }       

    一、View层和presenter的交互:
     
    View到presenter的调用(View--->presenter):
    上述代码,当用户点击按钮的时候,会执行一个账号和密码验证的业务逻辑。这个业务逻辑是封装在presenter中的。我们调用presenter的validateCredentials方法,传递参数,就可以执行账号和密码验证的业务逻辑。
     
    将业务逻辑封装到presenter层的好处是,我们可以在任何地方重用一个业务逻辑。比如,这个validateCredentials的业务逻辑,就可以被重用。
     
    presenter到View的调用(presenter--->view):
    在实例化presenter的时候,要提供一个LoginView的实现。
     public LoginPresenterImpl(LoginView loginView) {
            this.loginView = loginView;
            this.loginInteractor = new LoginInteractorImpl();
        }
    然后,LoginView接口定义了各种行为。presenter通过调用LoginView提供的行为,来实现presenter对View的控制。
    在这里,进行验证的时候,会有不同的情况,针对不同的情况,presenter层会调用LoginView中不同的方法,来告知用户当前的验证结果。
    如下:
     @Override public void onUsernameError() {
            loginView.setUsernameError();
            loginView.hideProgress();
        }
     
      @Override public void onPasswordError() {
            loginView.setPasswordError();
            loginView.hideProgress();
        }
     
       @Override public void onSuccess() {
            loginView.navigateToHome();
        }
     
    1).presenter层的业务逻辑实现:
    Presenter层只有一个业务逻辑,它由接口LoginPresenter接口声明:
    public interface LoginPresenter {
        public void validateCredentials(String username, String password);
    }
     
    public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {

        private LoginView loginView;
        private LoginInteractor loginInteractor;

        public LoginPresenterImpl(LoginView loginView) {
            this.loginView = loginView;
            this.loginInteractor = new LoginInteractorImpl();
        }

        @Override public void validateCredentials(String username, String password) {
            loginView.showProgress();
            loginInteractor.login(username, password, this);
        }

        @Override public void onUsernameError() {
            loginView.setUsernameError();
            loginView.hideProgress();
        }

        @Override public void onPasswordError() {
            loginView.setPasswordError();
            loginView.hideProgress();
        }

        @Override public void onSuccess() {
            loginView.navigateToHome();
        }
    }
    它的业务逻辑实现是由成员loginInterator来做的。
    然后,loginInterator要将判断结果通知LoginPresenterImpl,它通过调用OnLoginFinishedListener的接口中的方法。LoginPresenterImpl实现了OnLoginFinishedListener接口。
     
    通信由LoginInteratorImpl到LoginPresenterImpl(LoginInteratorImpl--->LoginPresenterImpl):
    OnLoginFinishedListener接口,定义了LoginPresenterImpl可以被LoginInteratorImpl调用的行为,用来告知LoginPresenterImpl验证的结果。
    public interface OnLoginFinishedListener {

        public void onUsernameError();

        public void onPasswordError();

        public void onSuccess();
    }
     
    public class LoginInteractorImpl implements LoginInteractor {

        @Override
        public void login(final String username, final String password, final OnLoginFinishedListener listener) {
            // Mock login. I'm creating a handler to delay the answer a couple of seconds
            new Handler().postDelayed(new Runnable() {
                @Override public void run() {
                    boolean error = false;
                    if (TextUtils.isEmpty(username)){
                        listener.onUsernameError();
                        error = true;
                    }
                    if (TextUtils.isEmpty(password)){
                        listener.onPasswordError();
                        error = true;
                    }
                    if (!error){
                        listener.onSuccess();
                    }
                }
            }, 2000);
        }
    }  
    通信由LoginPresenterImpl到LoginInteratorImpl(LoginPresenterImpl--->LoginInteratorImpl):
        @Override public void validateCredentials(String username, String password) {
            loginView.showProgress();
            loginInteractor.login(username, password, this);
        }
     
    二、View层:
    当前的Activity实现了LoginView接口,那么当前Activity是是LoginView,作为View层。
    它定义了供presenter调用的行为。
    public interface LoginView {
        public void showProgress();

        public void hideProgress();

        public void setUsernameError();

        public void setPasswordError();

        public void navigateToHome();
    }
    ---------------------------------------------------------------------
    Main模块
     
     
    一、View层:
    public interface MainView {

        public void showProgress();

        public void hideProgress();

        public void setItems(List<String> items);

        public void showMessage(String message);
    }
    这些是供presenter层调用的方法。
    这些方法中的代码是跟界面展示有关的。
     
    View层到Presenter层的通信,及View层的实现:
    public class MainActivity extends Activity implements MainView, AdapterView.OnItemClickListener {

        private ListView listView;
        private ProgressBar progressBar;
        private MainPresenter presenter;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = (ListView) findViewById(R.id.list);
            listView.setOnItemClickListener(this);
            progressBar = (ProgressBar) findViewById(R.id.progress);
            presenter = new MainPresenterImpl(this);

        }

        @Override protected void onResume() {
            super.onResume();
            presenter.onResume();
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }

        @Override public void showProgress() {
            progressBar.setVisibility(View.VISIBLE);
            listView.setVisibility(View.INVISIBLE);
        }


        @Override public void hideProgress() {
            progressBar.setVisibility(View.INVISIBLE);
            listView.setVisibility(View.VISIBLE);
        }


        @Override public void setItems(List<String> items) {
            listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
        }


        @Override public void showMessage(String message) {
            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
        }


        @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            presenter.onItemClicked(position);
        }
    }
     
    红色部分是MainView的行为,都是界面展示方面的代码。
    蓝色部分,是View层到Presenter通信的实现(View--->Presenter)。
     
    二、Presenter层:
    public interface MainPresenter {

        public void onResume();

        public void onItemClicked(int position);
    }
    它有两个业务逻辑要实现,一个是onResume(),一个是onItemClicked(int position)。
     
    Presenter层到View层的通信,及Presenter层的实现:
    public class MainPresenterImpl implements MainPresenter, OnFinishedListener {

        private MainView mainView;
        private FindItemsInteractor findItemsInteractor;

        public MainPresenterImpl(MainView mainView) {
            this.mainView = mainView;
            findItemsInteractor = new FindItemsInteractorImpl();
        }

        @Override public void onResume() {
            mainView.showProgress();
            findItemsInteractor.findItems(this);
        }

        @Override public void onItemClicked(int position) {
            mainView.showMessage(String.format("Position %d clicked", position + 1));
        }

        @Override public void onFinished(List<String> items) {
            mainView.setItems(items);
            mainView.hideProgress();

        }
    }
    红色部分是Presenter层到View层的通信实现(Presenter--->View)。
    onResume()方法和onItemClicked(int position)方法是Presenter实现的业务逻辑。
    其中FindItemsInteractor成员,负责创建一个List的实现。
     
    参考资料:
     http://antonioleiva.com/mvp-android/
  • 相关阅读:
    获取图片的大小(宽高):BytesIO
    python中url解析 or url的base64编码
    [extjs5学习笔记]第三十七节 Extjs6预览版都有神马新东西
    【翻译】Ext JS 6早期访问版本发布
    【翻译】Ext JS 6有什么新东西?
    【Java二十周年】Delphi转行java的一些小感触
    Cursor类取出数据
    通过服务修改widgetUI
    安卓笔记--Style的继承
    [ExtJS5学习笔记]第三十六节 报表组件mzPivotGrid
  • 原文地址:https://www.cnblogs.com/ttylinux/p/4483288.html
Copyright © 2011-2022 走看看