Wie verwenden von Android-MVVM-Muster mit Fragmenten?

Ersten bitte ich, entschuldigt sich über mein nicht gutes Deutsch.

Entwickelt ich viele Jahre Java-SE-software, und ich verwendet, um die Verwendung des MVC-design-pattern. Jetzt habe ich das entwickeln von android-apps, und ich bin nicht glücklich mit dem argument, das sagt, dass android bereits nutzt ein MVC-Muster, mit dem die xml-Dateien handeln, wie der Blick.

Ich habe eine Menge Forschung im web, aber es scheint, dass es keine Einstimmigkeit über dieses Thema. Einige verwenden das MVC-Muster, die anderen auf das MVP-Muster, aber ich bin meiner Meinung nach, gibt es keine Einhelligkeit.

Vor kurzem kaufte ich mir ein Buch (Android Best Practices, von Godfrey Nolan, Onur Cinar und David Truxall), und in Kapitel zwei finden Sie das MVC, MVVM-und Dependency Injection-patterns erklärt. Nach dem Versuch, alle von Ihnen, ich denke, dass für meine apps und meine Arbeit-Modus das beste ist das MVVM-pattern.

Ich finde dieses Muster sehr einfach zu verwenden, bei der Programmierung mit Aktivitäten, aber ich bin verwirrt über wie man es benutzt, wenn Programmierung mit Fragmenten. Ich reproduzieren das Beispiel für das MVVM-pattern angewendet, um einfache "todo-app", heruntergeladen von der Webseite "Android Best Practices" - Buch.

Die Anzeigen (Aktivität)

   package com.example.mvvm;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class TodoActivity extends Activity
{
    public static final String APP_TAG = "com.logicdrop.todos";

    private ListView taskView;
    private Button btNewTask;
    private EditText etNewTask;
    private TaskListManager delegate;

    /*The View handles UI setup only. All event logic and delegation
     *is handled by the ViewModel.
     */

    public static interface TaskListManager
    {
        //Through this interface the event logic is
        //passed off to the ViewModel.
        void registerTaskList(ListView list);
        void registerTaskAdder(View button, EditText input);
    }

    @Override
    protected void onStop()
    {
        super.onStop();
    }

    @Override
    protected void onStart()
    {
        super.onStart();
    }

    @Override
    public void onCreate(final Bundle bundle)
    {
        super.onCreate(bundle);

        this.setContentView(R.layout.main);

        this.delegate = new TodoViewModel(this);
        this.taskView = (ListView) this.findViewById(R.id.tasklist);
        this.btNewTask = (Button) this.findViewById(R.id.btNewTask);
        this.etNewTask = (EditText) this.findViewById(R.id.etNewTask);
        this.delegate.registerTaskList(taskView);
        this.delegate.registerTaskAdder(btNewTask, etNewTask);
    }
   }

Das Modell

 package com.example.mvvm;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

final class TodoModel
{
    //The Model should contain no logic specific to the view - only
    //logic necessary to provide a minimal API to the ViewModel.
    private static final String DB_NAME = "tasks";
    private static final String TABLE_NAME = "tasks";
    private static final int DB_VERSION = 1;
    private static final String DB_CREATE_QUERY = "CREATE TABLE " + TodoModel.TABLE_NAME + " (id integer primary key autoincrement, title text not null);";

    private final SQLiteDatabase storage;
    private final SQLiteOpenHelper helper;

    public TodoModel(final Context ctx)
    {
        this.helper = new SQLiteOpenHelper(ctx, TodoModel.DB_NAME, null, TodoModel.DB_VERSION)
        {
            @Override
            public void onCreate(final SQLiteDatabase db)
            {
                db.execSQL(TodoModel.DB_CREATE_QUERY);
            }

            @Override
            public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
                    final int newVersion)
            {
                db.execSQL("DROP TABLE IF EXISTS " + TodoModel.TABLE_NAME);
                this.onCreate(db);
            }
        };

        this.storage = this.helper.getWritableDatabase();
    }

    /*Overrides are now done in the ViewModel. The Model only needs
     *to add/delete, and the ViewModel can handle the specific needs of the View.
     */
    public void addEntry(ContentValues data)
    {
        this.storage.insert(TodoModel.TABLE_NAME, null, data);
    }

    public void deleteEntry(final String field_params)
    {
        this.storage.delete(TodoModel.TABLE_NAME, field_params, null);
    }

    public Cursor findAll()
    {
        //Model only needs to return an accessor. The ViewModel will handle
         //any logic accordingly.
        return this.storage.query(TodoModel.TABLE_NAME, new String[]
        { "title" }, null, null, null, null, null);
    }
   }

Das ViewModel

 package com.example.mvvm;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class TodoViewModel implements TodoActivity.TaskListManager
{
    /*The ViewModel acts as a delegate between the ToDoActivity (View)
     *and the ToDoProvider (Model).
     * The ViewModel receives references from the View and uses them
     * to update the UI.
     */

    private TodoModel db_model;
    private List<String> tasks;
    private Context main_activity;
    private ListView taskView;
    private EditText newTask;

    public TodoViewModel(Context app_context)
    {
        tasks = new ArrayList<String>();
        main_activity = app_context;
        db_model = new TodoModel(app_context);
    }

    //Overrides to handle View specifics and keep Model straightforward.

    private void deleteTask(View view)
    {
        db_model.deleteEntry("title='" + ((TextView)view).getText().toString() + "'");
    }

    private void addTask(View view)
    {
        final ContentValues data = new ContentValues();

        data.put("title", ((TextView)view).getText().toString());
        db_model.addEntry(data);
    }

    private void deleteAll()
    {
        db_model.deleteEntry(null);
    }

    private List<String> getTasks()
    {
        final Cursor c = db_model.findAll();
        tasks.clear();

        if (c != null)
        {
            c.moveToFirst();

            while (c.isAfterLast() == false)
            {
                tasks.add(c.getString(0));
                c.moveToNext();
            }

            c.close();
        }

        return tasks;
    }

    private void renderTodos()
    {
        //The ViewModel handles rendering and changes to the view's
        //data. The View simply provides a reference to its
        //elements.
        taskView.setAdapter(new ArrayAdapter<String>(main_activity,
                android.R.layout.simple_list_item_1,
                getTasks().toArray(new String[]
                        {})));
    }

    public void registerTaskList(ListView list)
    {
        this.taskView = list; //Keep reference for rendering later
        if (list.getAdapter() == null) //Show items at startup
        {
            renderTodos();
        }

        list.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            @Override
            public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id)
            { //Tapping on any item in the list will delete that item from the database and re-render the list
                deleteTask(view);
                renderTodos();
            }
        });
    }

    public void registerTaskAdder(View button, EditText input)
    {
        this.newTask = input;
        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(final View view)
            { //Add task to database, re-render list, and clear the input
                addTask(newTask);
                renderTodos();
                newTask.setText("");
            }
        });
    }
   }

Das problem ist, dass wenn ich versuchen Sie es zum reproduzieren dieses Muster bei Verwendung von Fragmenten, bin ich mir nicht sicher, wie Sie Vorgehen. Kann ich eine view-Modell und ein Modell für jedes fragment oder nur für die Aktivität, enthält diese Fragmente?

Mit dem klassischen Ansatz zu fragmentieren (das fragment ist eine innere Klasse innerhalb der Aktivität), ist es einfach zu interagieren mit der Aktivität oder den Zugriff auf die fragment-manager ändert, wenn ich aber entkoppeln Sie den code und die Logik der mein Programm außerhalb der Aktivität, die ich gesehen habe, brauche ich sehr oft Verweise auf die Aktivität in meinem ViewModel (keine Verweise auf die Ansichten der Tätigkeit, sondern verweist auf die Tätigkeit selbst).

Oder stellen Sie sich beispielsweise vor, dass die Aktivität mit Fragmenten, ist das arbeiten mit Daten in der Absicht, nicht von einem Modell (Datenbank-oder rest-service). Dann fühle ich, dass ich nicht brauchen, ein Modell. Vielleicht kann ich das Modell erstellen, wenn ich die Absicht in der Tätigkeit, aber ich habe das Gefühl, dass dies nicht korrekt ist (die Ansicht soll nicht in relation mit dem Modell, nur das viewmodel...).

Kann jemand mir eine Erklärung über die Verwendung des MVVM-Muster mit android bei der Verwendung von Fragmenten?

Vielen Dank im Voraus.

InformationsquelleAutor R. Campos | 2014-03-08

Schreibe einen Kommentar