0%

Android开发 使用MVC架构及状态设计模式开发

MVC架构的优点就不介绍了不过说实话,在小项目里用MVC,相对而言,确实复杂了。状态模式是指让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。下面的一个例子是模拟下载文件,不同的状态,点击按钮有不同的动作,使用Handler在Controller和Activity之间传递消息,以执行不同的操作,改变UI。范例独立出了Controller,并没有把Activity当Controller。 先看图: android_mvc 就是点击Download按钮,改变进度条。 先写Model.java:

package models;

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

import android.os.SystemClock;

public class Model {
    private String url;
    private long totalSize, downloadedSize;
    //监听器,可以添加多个
    private final List listeners = new ArrayList();
    //标记是否被取消
    private boolean cancelFlag = false;

    public Model(String url) {
        this.url = url;
    }

    public interface Listener {
        void onProgressUpdated(Model model);
        void onCompleted(Model model);
    }

    /**
     * 下载,耗时操作
     */
    public void download() {
        cancelFlag = false;
        totalSize = 100;
        while (downloadedSize < 100 && !cancelFlag) {
            SystemClock.sleep(1000);
            downloadedSize++;
            // 加上同步块,避免迭代时add或remove
            synchronized (listeners) {
                for (Listener listener : listeners) {
                    listener.onProgressUpdated(this);
                }
                if (downloadedSize == totalSize) {
                    for (Listener listener : listeners) {
                        listener.onCompleted(this);
                    }
                }
            }

        }
        // 取消后重置下载计数
        if (cancelFlag) {
            downloadedSize = 0;
        }

    }

    /**
     * 取消下载
     */
    public void cancel() {
        cancelFlag = true;
    }

    public void addListener(Listener listener) {
        synchronized (listeners) {
            listeners.add(listener);
        }

    }

    public void removeListener(Listener listener) {
        synchronized (listeners) {
            listeners.remove(listener);
        }

    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public long getTotalSize() {
        return totalSize;
    }

    public void setTotalSize(long totalSize) {
        this.totalSize = totalSize;
    }

    public long getDownloadedSize() {
        return downloadedSize;
    }

    public void setDownloadedSize(long downloadedSize) {
        this.downloadedSize = downloadedSize;
    }

}

接口ControllerProtocol,用于保存常量,这样,只要实现了该接口的类都会有相同的常量,这里主要是保存Message的what值。

package controllers;

/**
 * 用于共享常量,所有实现该接口的类都可以使用这些常量
 * @author fhp
 *
 */
public interface ControllerProtocol {
    /**Message的what值**/
    public final int W_REQUEST_DOWNLOAD=1,W_REQUEST_CANCEL=2, W_TOAST=3,W_UPDATE=4,W_COMPLETE=5;
}

ControllerState.java,三种不同状态:未下载,正在下载,下载完成

package controllers;

import android.os.Message;
/**
 * 不同状态
 * @author fhp
 *
 */
public abstract class ControllerState {
    protected Controller controller;
    public ControllerState(Controller controller)
    {
        this.controller=controller;
    }
    public abstract boolean handleMessage(Message msg);
    
}
/**
 * 未开始下载状态,默认值
 * @author fhp
 *
 */
final class NotStartState extends ControllerState implements ControllerProtocol{

    public NotStartState(Controller controller) {
        super(controller);
        // TODO 自动生成的构造函数存根
    }

    @Override
    public boolean handleMessage(Message msg) {
        // TODO 自动生成的方法存根
        switch(msg.what)
        {
        case W_REQUEST_DOWNLOAD:
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "开始下载!");
            controller.changeState(new DownloadingState(controller));
            break;
        case W_REQUEST_CANCEL:
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "下载未开始,不用取消!");
            break;
        }
        return false;
    }
    
}
/**
 * 正在下载的状态
 * @author fhp
 *
 */
final class DownloadingState extends ControllerState implements ControllerProtocol{

    public DownloadingState(final Controller controller) {
        super(controller);
        // 切换到下载状态时,开始下载。不能用Controller里的HandlerThread下载,虽然不会阻塞UI,但会阻塞消息传递
        new Thread(){
            public void run()
            {
                controller.getModel().download();
            }
        }.start();
    }

    @Override
    public boolean handleMessage(Message msg) {
        // TODO 自动生成的方法存根
        switch(msg.what)
        {
        case W_REQUEST_DOWNLOAD:
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "下载已开始!");
            break;
        case W_REQUEST_CANCEL:
            controller.getModel().cancel();
            controller.changeState(new NotStartState(controller));
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "下载取消!");
            break;
        }
        return false;
    }
    
}
/**
 * 下载完成状态
 * @author fhp
 *
 */
final class CompletedState extends ControllerState implements ControllerProtocol{

    public CompletedState(Controller controller) {
        super(controller);
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch(msg.what)
        {
        case W_REQUEST_DOWNLOAD:
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "下载已完成!");
            break;
        case W_REQUEST_CANCEL:
            controller.notifyOutboxHandlers(W_TOAST, 0, 0, "下载完成,不能取消!");
            break;
        }
        return false;
    }
    
}

Controller.java:

package controllers;

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

import models.Model;
import models.Model.Listener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;


public class Controller implements Handler.Callback,ControllerProtocol {
    //收信Handler
    private Handler inBoxHandler;
    //发信Handler
    private List outBoxHandlers = new ArrayList();

    private Model model;
    //状态模式,状态改变,改变state
    private ControllerState state;

    public Controller(Model model) {
        this.model = model;
        // 默认没开始状态
        this.state = new NotStartState(this);

        inBoxHandler = new Handler(this);
        //增加监听器
        this.model.addListener(new Listener() {
            
            @Override
            public void onProgressUpdated(Model model) {
                // TODO 自动生成的方法存根
                notifyOutboxHandlers(W_UPDATE,0,0,model);
            }
            
            @Override
            public void onCompleted(Model model) {
                // TODO 自动生成的方法存根
                notifyOutboxHandlers(W_COMPLETE,0,0,model);
                changeState(new CompletedState(Controller.this));
            }
        });
        
    }

    /**
     * 改变状态
     * 
     * @param state
     */
    public void changeState(ControllerState state) {
        this.state = state;
    }

    public void addOutBoxHandler(Handler handler) {
        outBoxHandlers.add(handler);
    }

    public Handler getInBoxHandler() {
        return inBoxHandler;
    }

    public Model getModel() {
        return model;
    }

    @Override
    public boolean handleMessage(Message msg) {
        // 收到消息后(这里就是点击事件),转发给ControllerState处理,不同的State处理方法不同
        return state.handleMessage(msg);
    }
    /**
     * 消息发给所有的Handler,例子里只有一个
     * @param what
     * @param arg1
     * @param arg2
     * @param obj
     */
    public void notifyOutboxHandlers(int what, int arg1, int arg2, Object obj) {
        for (Handler handler : outBoxHandlers) {
            Message msg = Message.obtain(handler, what, arg1, arg2, obj);
            msg.sendToTarget();
        }

    }

}

最后是activity:

package com.pocketdigi.mvcdemo;

import models.Model;
import controllers.Controller;
import controllers.ControllerProtocol;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements Handler.Callback,OnClickListener,ControllerProtocol{
    
    private TextView tv_count;
    private Button btn_down,btn_cancel;
    private ProgressBar progressBar;
    //独立的Controller
    private Controller controller;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViews();
        
        controller=new Controller(new Model("http://www.pocketdigi.com"));
        controller.addOutBoxHandler(new Handler(this));
        
    }
    
    private void findViews()
    {
        tv_count=(TextView)findViewById(R.id.tv_count);
        btn_down=(Button)findViewById(R.id.btn_down);
        btn_cancel=(Button)findViewById(R.id.btn_cancel);
        progressBar=(ProgressBar)findViewById(R.id.progressBar);
        btn_down.setOnClickListener(this);
        btn_cancel.setOnClickListener(this);
    }

    @Override
    public boolean handleMessage(Message msg) {
        // TODO 自动生成的方法存根
        switch(msg.what)
        {
        case W_TOAST:
            String string=(String)msg.obj;
            showToast(string);
            break;
        case W_UPDATE:
            Model model=(Model)msg.obj;
            double percent=model.getDownloadedSize()/(double)model.getTotalSize()*100;
            progressBar.setProgress((int)percent);
            tv_count.setText(String.format("%1$.2f%%", percent));
            break;
        case W_COMPLETE:
            showToast("下载完成");
            break;
        }
        return false;
    }
    private void showToast(String string)
    {
        Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onClick(View v) {
        switch(v.getId())
        {
        case R.id.btn_down:
            controller.getInBoxHandler().sendEmptyMessage(W_REQUEST_DOWNLOAD);
            break;
        case R.id.btn_cancel:
            controller.getInBoxHandler().sendEmptyMessage(W_REQUEST_CANCEL);
            break;
        }
    }
       
}

源码下载链接: http://pan.baidu.com/s/1o6rv0BS