Android 是不是支持 MVC(模型视图控制器)结构?
Posted
技术标签:
【中文标题】Android 是不是支持 MVC(模型视图控制器)结构?【英文标题】:Does Android supports MVC (Model View Controller) Structure?Android 是否支持 MVC(模型视图控制器)结构? 【发布时间】:2012-08-21 19:01:40 【问题描述】:我想知道,如果android支持MVC(模型视图控制器)结构?如果支持那么 1. 什么是控制器? 2.什么是型号?和 3. 什么是视图?
请清除我。我对此有些困惑。
【问题讨论】:
***.com/questions/2925054/mvc-pattern-in-android 的可能重复项 从这里开始查看我的博文Android Architecture: MV? 【参考方案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
类,但它 但是,确实处理向用户显示窗口并处理 该窗口的事件(onCreate
、onPause
等)。这意味着,当您使用 MVC 模式时,您的控制器 实际上将是一个伪 View-Controller。既然是处理 向用户显示一个带有附加视图组件的窗口 您已使用
setContentView
添加到它,并且还为 至少各种活动生命周期事件。在 MVC 中,控制器应该是主入口点。哪一个 如果将其应用于android时是这种情况,则有点值得商榷 开发,因为
activity
是大多数人的自然切入点 应用程序。
所以,android 中的伪 MVC:
模型 = 具有主要业务逻辑的实体或类
视图 = 布局、资源和小部件,例如EditText
控制器 = Activity
, Adaptor
【讨论】:
酷!但是这些片段在这个架构中去哪里了? 我完全同意你的看法!【参考方案4】:模型 = 内容提供者。
控制器 = 活动、片段或服务。
视图 = XML 布局。
【讨论】:
【参考方案5】:MVC 已经在 Android 中实现了
View = 布局、资源和内置类,例如从 android.view.View 派生的 Button。
控制器 = 活动和片段
Model = 实现应用逻辑的类
【讨论】:
以上是关于Android 是不是支持 MVC(模型视图控制器)结构?的主要内容,如果未能解决你的问题,请参考以下文章