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

© 2013, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记

发表评论

电子邮件地址不会被公开。 必填项已用*标注