【问题标题】:Does Android supports MVC (Model View Controller) Structure?Android 是否支持 MVC(模型视图控制器)结构?
【发布时间】:2012-08-21 19:01:40
【问题描述】:

我想知道,如果Android支持MVC(模型视图控制器)结构?如果支持那么 1. 什么是控制器? 2.什么是型号?和 3. 什么是视图?

请清除我。我对此有些困惑。

【问题讨论】:

标签: android model-view-controller


【解决方案1】:

不是真正的 MVC,而是通过 Room 和 LiveData 变得更加 MVC

在经典 MVC 中,控制器是关于决策的,即下一步要运行哪个动作。视图从模型中读取数据并更新它自己的字段。

在 Android 活动中,两者都做,它们决定运行什么动作来响应事件,并设置布局的字段。他们还从模型中读取数据并连接小部件。这些活动结合了经典控制器和经典视图两者的逻辑任务。

这就是为什么在大多数情况下我不会谈论 MVC。控制器和视图之间没有明确的分离。 Java 代码和 XML 资源之间有一个清晰的分离。这是有道理的,因为在更大的团队中,不同的人负责视觉布局和编程。

您仍然可以编写自己的视图组件并将这部分代码作为视图来处理。它只是经典视图的被动部分,而逻辑已经在活动和片段中加入了控制器。我不会谈论视图,而是组件或小部件。越智能的小部件,它们再次占用的经典视图的逻辑就越多。

另一方面,如果您应用 Room 之类的库,Android 将再次变得更加 MVC。 Room 和 LiveData 使视图能够观察模型的变化,一直到数据库的变化。如果您清楚地分离视图内容并将控制器简化为决策制定,那么您可以以某种方式构建您的架构,它确实再次配得上 MVC 的名称。

底线

这取决于开发人员。可以将真正的 MVC 应用到 Android 上,但不是默认情况。

【讨论】:

    【解决方案2】:

    实现 MVC 模式的主要目标是,这样做之后您可以“拉出”其中的任何一个并添加一个新的,而无需对其他两个进行很少或没有必要的更改。

    模型:所有关于数据。操作了什么,存储了什么以及如何操作。

    视图:所有关于 UI 或演示的信息。显示什么以及如何显示。

    控制器:事件处理程序。指示其他两个响应事件何时运行。

    在 Android 中,MVC 的这种实现具有以类的形式扩展 Activity 类的控制器。毕竟,正是此类最初接收构成 Android Activity 生命周期的“事件”(即 onStart()、onCreate()、onSuspend()、onStop()、onResume()、onDestroy)。这个生命周期可能会随着 Android 的发展而改变,因此将其表示为 MVC 模式的控制器组件是有意义的。

    同样,通过这个 MVC 实现,我可以取出三个组件中的任何一个,然后放入一个全新的界面(视图)、一个全新的数据库(模型)或一个新的活动生命周期(控制器)其他两个没有变化。唯一需要的是每个组件都尊重下面列出的样板模板。

    在这个实现中,三个MVC组件分别用三个java类来表示:appView.java、appController.java、appModel.java

    查看每个类时,记下成员变量 mController、mAppView 和 mAppModel,并查看它们在每个 java 文件中的引用方式和时间。 这些成员变量是允许每个组件相互引用的“挂钩”。

    此外,您会注意到 mAppModel 进一步分解并使用了一个名为 dbHelper 的附加类。这使您可以将“什么”数据与“如何”操作和存储数据分开。

    public class appController extends Activity {
    
        appView mAppView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mAppView = new appView(this);
    
            mAppView.onCreate(savedInstanceState);
        }
    
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
    
            return mAppView.onCreateOptionsMenu(menu);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
    
            boolean result;
    
            switch (item.getItemId()) {
                case ....
    
                    return true;
    
                case ....
    
    
                    return true;
    
                default:
    
                    result = mAppView.onOptionsItemSelected(item);
            }
    
            if ( !result )
                result = super.onOptionsItemSelected(item);
    
            return result;
        }
    
    
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    
            mAppView.onCreateContextMenu(menu, v, menuInfo);
        }
    
    
        @Override
        public boolean onContextItemSelected(MenuItem item) {
    
            return mAppView.onContextItemSelected(item);
        }
    
        // When a startActivityForResult() is called
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            mAppView.onActivityResult(requestCode, resultCode, data);
        }
    
    
        @Override
        protected void onStop(){
            super.onStop();
    
            mAppView.onStop();
        }
    
        @Override
        protected void onRestart(){
            super.onRestart();
    
            mAppView.onRestart();
        }
    
        @Override
        protected void onDestroy(){
              super.onDestroy();
    
              mAppView.onDestroy();
    
              mAppView = null;
        }
    

    控制器 appController 实现了大部分“活动生命周期”方法,并依次调用视图 appView 中的方法。这意味着标准的生命周期方法,onStop、onResume、onDestroy 等不仅在 Controller 中实现,而且在此 MVC 模式的 View 部分中实现。稍后您会看到模型部分也是如此。

    您可以在下面的 View 实现中看到 appView,其成员变量 mController 用于访问 Activity 方法,但允许将 Activity(控制器)与 UI(布局、菜单等)分离.

    public class appView {
    
    
        private Activity mController;
    
        private Context mContext;
    
        private appModel mAppModel;
    
    
        public appView(Activity activity) {
            this((Context) activity);
    
            mController = activity;
        }
    
        // This can be called when there is not activity available.
        public appView(Context context){
    
            mContext = context;
    
            mAppModel = new appModel(this);
        }
    
        protected void onCreate(Bundle savedInstanceState) {
    
            mController.setContentView(R.layout.whatever_you_want_activity);
    
            btnNewToDo = (Button) mController.findViewById(.....
    
            // The New button.
            btnNewToDo.setOnClickListener(......
    
            lvToDos = (ListView) mController.findViewById(......
    
            // One click will edit that selected item.
            lvToDos.setOnItemClickListener(........
        }
    
        public boolean onCreateOptionsMenu(Menu menu) {
    
            MenuInflater inflater = mController.getMenuInflater();
    
            inflater.inflate(R.menu.whatever_you_want_menu, menu);
    
            return true;
        }
    
    
        public boolean onOptionsItemSelected(MenuItem item) {
    
           ....
        }
    
    
        protected void onStop(){
    
            mAppModel.onStop();
        }
    
        protected void onRestart(){
    
            mAppModel.onRestart();
        }
    
        protected void onDestroy() {
    
            mController = null;
    
            mContext = null;
    
            if(mAppModel != null ){
    
                mAppModel.onDestroy();
    
                mAppModel = null;
            }
        }
    }
    

    型号如下。 查看此类如何在其构造函数中接收视图和控制器。控制器被视为 Context 类型,而不是 Activity。这允许您涉及任何 Context 类型的对象,而不必是 Activity 对象。

    此外,您会看到在构造函数中引入了一个帮助器类 dbHelper。

    public class appModel {
    
        private appView mAppView;
        private Context mContext;
    
        // Holds the database helper
        private dbHelper mDBHelper;
    
    
        public appModel(appView appView){
    
            mAppView = appView;
    
            mContext = mAppView.getContext();
    
            mDBHelper = new dbHelper(mContext);
        }
    
    
        public boolean open() {
    
            if (mDBHelper == null) return false;
    
            return mDBHelper.open().isOpen();
        }
    
    
        public void close(){
    
            mDBHelper.close();
        }
    
        // The App might get destroyed with calling onDestroy, and so close it.
        protected void onStop(){
    
            // close the db connection...
            close();
        }
    
        protected void onRestart() {
    
            // db likely closed.
            open();
        }
    
        protected void onDestroy(){
    
            mAppView = null;
    
            mContext = null;
    
            mDBHelper.onDestroy();
    
            mDBHelper = null;
        }
    }
    

    如下所示,SQLite 是此应用程序中使用的数据库。但是,切换出这个帮助程序类 dbHelper,您可以使用完全不同的数据库,而其他组件也不会更明智。

    下面包含一些基本方法(打开、关闭等),可让您了解此处执行的功能。此外,请注意 onDestroy() 方法在这里关闭数据库连接。它由上面的 View 调用,当它被销毁时又由 Controller 调用。

    正是这个帮助类知道数据库中字段的名称。 有了这个实现,视图、控制器甚至模型都不需要知道所使用的数据库类型甚至字段名称。

    public class dbHelper extends SQLiteOpenHelper {
    
        private SQLiteDatabase mDB;
    
        private Context mContext;
    
    
        static final String DATABASE_NAME = "whatever";
    
        static final String DATABASE_FILE = DATABASE_NAME + ".db";
    
        static final String DBKEY_FIELD = "rowid";
    
        static final int DATABASE_VERSION = 5;
    
        // SQL Statement to create a new database.
        private static final String DATABASE_CREATE = "CREATE TABLE IF NOT EXISTS " + DATABASE_NAME
                + "(....  );";
    
        // SQL statement used to upgrade the database.
        private final String ALTER_TABLE = "ALTER TABLE " + DATABASE_NAME + " ADD COLUMN anewfield VARCHAR;";
    
        private final String SELECT_ALL = "SELECT " + DBKEY_FIELD + " AS _id, * FROM " + DATABASE_NAME + " ORDER BY somefield ASC";
    
        private static final String DROP_TABLE = "DROP TABLE IF EXISTS " + DATABASE_NAME;
    
    
        public dbHelper(Context controller) {
            super(controller, DATABASE_FILE, null, DATABASE_VERSION);
    
            mContext = controller;
        }
    
        // Called when no database exists or if there is a new 'version' indicated.
        @Override
        public void onCreate(SQLiteDatabase db) {
    
            db.execSQL(DATABASE_CREATE);
        }
    
    
        public dbHelper open() {
    
            try {
    
                mDB = getWritableDatabase();
    
            } catch (SQLException ex) {
    
                if (mDB != null && mDB.isOpen()) {
    
                    mDB.close();
                }
    
                if (mDB != null) {
    
                    mDB = null;
                }
            }
    
            return this;
        }
    
    
        public boolean isOpen() {
    
            return mDB != null && mDB.isOpen();
        }
    
    
        public void close() {
            super.close();
    
            // It's good to lose the reference here with the connection closed.
            mDB = null;
        }
    
    
        protected void onDestroy() {
    
            close();
    
            // Just making sure.
            mDB = null;
    
            mContext = null;
        }
    
    
        public SQLiteDatabase getDatabaseInstance() {
    
            return mDB;
        }
    
    
    
        private Cursor runQuery(String sqlStmt) {
    
            Cursor records;
    
            try {
    
                records = mDB.rawQuery(sqlStmt, null);
    
            } catch (RuntimeException ex) {
    
                // If something goes wrong, return an empty cursor.
                records = new MatrixCursor(new String[]{"empty"});
            }
    
            return records;
        }
    
    
        protected boolean dropTable() {
    
            boolean dropped;
    
            try {
    
                mDB.execSQL("DROP TABLE IF EXISTS " + DATABASE_NAME);
    
                dropped = true;
    
            } catch (SQLException ex) {
    
                dropped = false;
            }
    
            return dropped;
        }
    
    
        @Override
        public void onConfigure(SQLiteDatabase db) {
        }
    
        @Override
        public void onOpen(SQLiteDatabase db) {
        }
    
        // Called when the database needs to be upgraded to the current version.
    @Override
        public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) {
    
            if ( _oldVersion >= _newVersion){
    
                Log.w(mContext.getClass().getSimpleName(), "Cannot 'upgrade' from version " + _newVersion + " to " + _oldVersion + ". Upgrade attempt failed.");
            }
    
            try {
    
                _db.execSQL(ALTER_TABLE);
    
            }catch(RuntimeException ex){
    
                Log.e(mContext.getClass().getSimpleName(), "Database upgrade failed. Version " + _oldVersion + " to " + _newVersion);
    
                throw ex;
            }
    
            // Log the version upgrade.
            Log.i(mContext.getClass().getSimpleName(), "Database upgrade. Version " + _oldVersion + " to " + _newVersion);
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      Which design patterns are used on Android?

      模型-视图-控制工作正常

      实际的Activity 类没有扩展android 的View 类,但它 但是,确实处理向用户显示窗口并处理 该窗口的事件(onCreateonPause 等)。

      这意味着,当您使用 MVC 模式时,您的控制器 实际上将是一个伪 View-Controller。既然是处理 向用户显示一个带有附加视图组件的窗口 您已使用 setContentView 添加到它,并且还为 至少各种活动生命周期事件。

      在 MVC 中,控制器应该是主入口点。哪一个 如果将其应用于android时是这种情况,则有点值得商榷 开发,因为activity 是大多数人的自然切入点 应用程序。

      所以,android 中的伪 MVC:

      模型 = 具有主要业务逻辑的实体或类

      视图 = 布局、资源和小部件,例如EditText

      控制器 = Activity , Adaptor

      【讨论】:

      • 酷!但是这些片段在这个架构中去哪里了?
      • 我完全同意你的看法!
      【解决方案4】:

      模型 = 内容提供者。

      控制器 = 活动、片段或服务。

      视图 = XML 布局。

      【讨论】:

        【解决方案5】:

        MVC 已经在 Android 中实现了

        View = 布局、资源和内置类,例如从 android.view.View 派生的 Button。

        控制器 = 活动和片段

        Model = 实现应用逻辑的类

        【讨论】:

          猜你喜欢
          • 2013-12-06
          • 1970-01-01
          • 1970-01-01
          • 2012-09-03
          • 1970-01-01
          • 2015-01-19
          • 2023-03-03
          • 2011-09-12
          • 2011-02-02
          相关资源
          最近更新 更多