close

參考資料: Android Best Practices

這篇是一個範例如何將傳統的寫寫法變成MVC的架構

傳統寫法: there are two Java files we will work with, TodoActivity.java, shown in Listing 2-1, 
and TodoProvider.java, which you’ll see in Listing 2-2.

Listing 2-1.  TodoActivity.java
package com.logicdrop.todos;
 
import java.util.ArrayList;
import java.util.List;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.os.StrictMode;
 
public class TodoActivity extends Activity
{
   public static final String APP_TAG = "com.logicdrop.todos";
 
   private ListView taskView;
   private Button btNewTask;
   private EditText etNewTask;
   private TodoProvider provider;
 
   private OnClickListener handleNewTaskEvent = new OnClickListener()
   {
       @Override
       public void onClick(final View view)
       {
          Log.d(APP_TAG, "add task click received");
 
          TodoActivity.this.provider.addTask(TodoActivity.this
                 .getEditText()
                 .getText()
                 .toString()); 
          TodoActivity.this.renderTodos();
       }
   };

   @Override
   protected void onStart()
   {
       super.onStart();
   }
   private void createPlaceholders()
   {
       this.getProvider().deleteAll();
       if (this.getProvider().findAll().isEmpty())
       {
          List<String> beans = new ArrayList<String>();
          for (int i = 0; i < 10; i++)
          {
              String title = "Placeholder " + i;
              this.getProvider().addTask(title);
              beans.add(title);
          }
       }
   }
   EditText getEditText()
   {
       return this.etNewTask;
   }
   private TodoProvider getProvider()
   {
       return this.provider;
   }
   private ListView getTaskView()
   {
       return this.taskView;
   }
   public void onCreate(final Bundle bundle)
   {
        super.onCreate(bundle);
        this.setContentView(R.layout.main);
       this.provider = new TodoProvider(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.btNewTask.setOnClickListener(this.handleNewTaskEvent);
       this.showFloatVsIntegerDifference(); 
       this.createPlaceholders(); 
       this.renderTodos();
  }
 
       private void renderTodos()
       {
       List<String> beans = this.getProvider().findAll();
 
       Log.d(APP_TAG, String.format("%d beans found", beans.size()));
 
       this.getTaskView().setAdapter(
              new ArrayAdapter<String>(this,
                     android.R.layout.simple_list_item_1, beans
                            .toArray(new String[]
                            {})));
 
       this.getTaskView().setOnItemClickListener(new OnItemClickListener()
       {
          @Override
          public void onItemClick(final AdapterView<?> parent,
                 final View view, final int position, final long id)
          {
              Log.d(APP_TAG, String.format(
                     "item with id: %d and position: %d", id, position));
 
              TextView v = (TextView) view;
              TodoActivity.this.getProvider().deleteTask(
                     v.getText().toString());
              TodoActivity.this.renderTodos();
          }
       });
   } 
}

TodoActivity.java controls the layout of the app, and TodoProvider.java, shown in Listing 2-2, 
manages the data for the items you add to your list. In the app we’ve populated it with a list of initial 
placeholder items.
Listing 2-2.  TodoProvider.java

package com.logicdrop.todos;
 
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;
 
import com.logicdrop.todos.TodoActivity;
 
public class TodoProvider
{
   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 " + TABLE_NAME + " (id integer 
primary key autoincrement, title text not null);";
 
   private SQLiteDatabase storage;
   private SQLiteOpenHelper helper;
 
   public TodoProvider(final Context ctx)
   {
       this.helper = new SQLiteOpenHelper(ctx, DB_NAME, null, DB_VERSION)
       {
          @Override
          public void onCreate(final SQLiteDatabase db)
          {
              db.execSQL(DB_CREATE_QUERY);
          }
 
          @Override
          public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
                 final int newVersion)
          {
              db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
              this.onCreate(db);
          }
       };
 
       this.storage = this.helper.getWritableDatabase();
   }
 
   public synchronized void addTask(final String title)
   {
       ContentValues data = new ContentValues();
       data.put("title", title);
 
       this.storage.insert(TABLE_NAME, null, data);
   }
 
   public synchronized void deleteAll()
   {
       this.storage.delete(TABLE_NAME, null, null);
   }
 
   public synchronized void deleteTask(final long id)
   {
       this.storage.delete(TABLE_NAME, "id=" + id, null);
   }
   public synchronized void deleteTask(final String title)
   {
       this.storage.delete(TABLE_NAME, "title='" + title + "'", null);
   }
 
   public synchronized List<String> findAll()
   {
       Log.d(TodoActivity.APP_TAG, "findAll triggered");
 
       List<String> tasks = new ArrayList<String>();
 
       Cursor c = this.storage.query(TABLE_NAME, new String[] { "title" }, null, null, null, null, null);
 
       if (c != null)
       {
          c.moveToFirst(); 
          while (c.isAfterLast() == false)
          {
              tasks.add(c.getString(0));
              c.moveToNext();
          } 
          c.close();
       } 
       return tasks;
   }
}

 

MVC 架構設計Android 
MVC (Model-View-Controller) 

The Model
The MVC Model component, shown in Listing 2-10, largely replaces the ToDoProvider.java code from before.
Listing 2-10.  MVC Model code

final class TodoModel
{
    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();
    }
 
    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()
    {
        Log.d(TodoActivity.APP_TAG, "findAll triggered");
 
        final Cursor c = this.storage.query(TodoModel.TABLE_NAME, new String[]
                { "title" }, null, null, null, null, null);
 
        return c;
    }
}


The View
The View code in MVC, shown in Listing 2-11, is a modified version of the ToDoActivity.java 
code from before. Any UI changes now happen here, and the control code is now moved to the 
ToDoController.java file. 
Listing 2-11.  MVC View code


public class TodoActivity extends Activity
{
    public static final String APP_TAG = "com.example.mvc";
 
    private ListView taskView;
    private Button btNewTask;
    private EditText etNewTask;
 
    /*Controller changes are transparent to the View. UI changes won't
     *affect logic, and vice-versa. See below: the TodoModel has
     * been replaced with the TodoController, and the View persists
     * without knowledge that the implementation has changed.
     */
    private TodoController provider;
 
    private final OnClickListener handleNewTaskEvent = new OnClickListener()
    {
        @Override
        public void onClick(final View view)
        {
            Log.d(APP_TAG, "add task click received");
 
            TodoActivity.this.provider.addTask(TodoActivity.this
                    .etNewTask
                    .getText()
                    .toString());
 
            TodoActivity.this.renderTodos();
        }
    };
 
    @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.provider = new TodoController(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.btNewTask.setOnClickListener(this.handleNewTaskEvent);
 
        this.renderTodos();
    }
 
    private void renderTodos()
    {
        final List<String> beans = this.provider.getTasks();
 
        Log.d(TodoActivity.APP_TAG, String.format("%d beans found", beans.size()));
 
        this.taskView.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,
                beans.toArray(new String[]
                        {})));
 
        this.taskView.setOnItemClickListener(new OnItemClickListener()
        {
            @Override
            public void onItemClick(final AdapterView<?> parent, final View view, final int 
position, final long id)
            {
                Log.d(TodoActivity.APP_TAG, String.format("item with id: %d and position: %d", id, 
position));
 
                final TextView v = (TextView) view;
                TodoActivity.this.provider.deleteTask(v.getText().toString());
                TodoActivity.this.renderTodos();
            }
        });
    }
}
The Controller
Shown in Listing 2-12, the controller binds the UI to the data but also creates a layer of separation 
between the model and view code above. This interface between the two layers provides a 
framework for the code to expand and for new developers to follow the MVC pattern to know what 
new code belongs where.
Listing 2-12.  MVC Controller code

public class TodoController {
    /*The Controller provides data from the Model for the View to bind to the UI.  */
     private TodoModel db_model;
    private List<String> tasks;
    public TodoController(Context app_context)
    {
        tasks = new ArrayList<String>();
        db_model = new TodoModel(app_context);
    }
    public void addTask(final String title)
    {
        final ContentValues data = new ContentValues();
        data.put("title", title);
        db_model.addEntry(data);
    }
    //Overrides to handle View specifics and keep Model straightforward.
    public void deleteTask(final String title)
    {
        db_model.deleteEntry("title='" + title + "'");
    }
    public void deleteTask(final long id)
    {
        db_model.deleteEntry("id='" + id + "'");
    }
    public void deleteAll()
    {
        db_model.deleteEntry(null);
    }
    public List<String> getTasks()
    {
        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;
    }
}

The layout for the To Do List screen is defined in the Layout.xml file, It is also shown in Listing 2-3.
Listing 2-3.  Layout.xml
<?xml version="1.0" encoding="utf-8"?> (change to LinearLayout)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget31"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TableRow
        android:id="@+id/row"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/tasklist"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/etNewTask"
            android:layout_width="200px"
            android:layout_height="wrap_content"
            android:text=""
            android:textSize="18sp" >
        </EditText>
 
        <Button
            android:id="@+id/btNewTask"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@+string/add_button_name" >
        </Button>
    </TableRow>
    <ListView
        android:id="@+id/tasklist"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >
    </ListView>
</RelativeLayout>

arrow
arrow
    文章標籤
    mvc
    全站熱搜

    stanley 發表在 痞客邦 留言(0) 人氣()