8

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

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

4

5 回答 5

24

Android 上使用了哪些设计模式?

模型视图控制工作正常

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

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

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

所以,android中的伪MVC:

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

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

控制器= Activity,Adaptor

在此处输入图像描述

于 2012-08-27T09:56:04.867 回答
5

模型= 内容提供者。

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

视图= XML 布局。

于 2012-08-27T09:37:54.267 回答
3

MVC 已经在 Android 中实现

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

控制器 = 活动和片段

模型 = 实现应用程序逻辑的类

于 2012-08-27T09:43:00.863 回答
1

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

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

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

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

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

另一方面,如果你应用像 Room 这样的库,Android 会再次变得更像 MVC。Room 和 LiveData 使视图能够观察模型的变化,一直到数据库的变化。如果您干净地分离视图内容并将控制器减少到决策制定,您可以以某种方式构建您的架构,它真的值得再次命名为 MVC。

底线

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

于 2018-02-08T13:38:29.707 回答
0

实现 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);
    }

}
于 2015-03-08T00:38:27.163 回答