安卓CVB模式

传统的软件设计MVC模型在WEB开发中很流行,也很合适,因为Servlet的灵活性,使用Servlet中与UI、业务相关的代码可以完全分离。WEB项目中,Servlet充当了Controller的角色,HTML、JSP等视图技术充当了View的角色,JavaBean、DAO等充当于Modle的角色。
虽然MVC模式在WEB端大红大紫,但是,在安卓开发中,MVC并不实用,安卓开发若是强行使用MVC的话,定会使得程序更加复杂,更加难以维护。
因为,在Android开发中,View主要是由资源文件(如layout、values、drawable等)和View的子类构成,而这些View又主要由Activity来控制显示,由此,Activity就是View的Controller(控制器),因为与View相关的操作都在Activity中完成,所以Activity与View之间就紧密相联,这样Activity与View之间的耦合度就非常的高,往往使得一个Activity中充满了上千行与View相关操作的代码。
在Android开发中,业务层的代码,往往都会与Activity打交道,因为业务代码要与View打交道。这样,在Activity中同时也充满了很多与业务相关的代码,就使得一个Activity中的代码数量更多庞大了。
因此在安卓传统开发中,一个Activity往往都容易达到上千行代码,维护起来也相当困难。

本文要讲解的一个安卓端开发模式,虽然功能和火热的MVP模式相同,但是,设计理念也相同,但是,实现方式并不一样,专注点也不一样。本文讲解的开发模式,专注与将UI与业务相关的代码从Activity中抽离出来,使得Activity中代码量极速减少,同时,将业务分离的更加具体,使得Activity专注于Controller的工作,View专注于做View的工作,业务专注于业务处理,我称之MVB模式(Controller、View、Business)。
这里写图片描述

以下,直接上源码说明CVB模式
(注意,源码中使用了XUtil框架)
1、源码结构图
这里写图片描述

2、ExampleViewHolder

package com.winway.collectiondata.viewholder;

import com.lidroid.xutils.view.annotation.ViewInject;
import com.winway.collectiondata.R;

import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class ExampleViewHolder {
    @ViewInject(R.id.title)
    public TextView titleTV;
    @ViewInject(R.id.username)
    public EditText usernameET;
    @ViewInject(R.id.password)
    public EditText passwordET;
    @ViewInject(R.id.code)
    public EditText validateCodeET;
    @ViewInject(R.id.login)
    public Button enterBT;

    public TextView getTitleTV() {
        return titleTV;
    }

    public void setTitleTV(TextView titleTV) {
        this.titleTV = titleTV;
    }

    public EditText getUsernameET() {
        return usernameET;
    }

    public void setUsernameET(EditText usernameET) {
        this.usernameET = usernameET;
    }

    public EditText getPasswordET() {
        return passwordET;
    }

    public void setPasswordET(EditText passwordET) {
        this.passwordET = passwordET;
    }

    public EditText getValidateCodeET() {
        return validateCodeET;
    }

    public void setValidateCodeET(EditText validateCodeET) {
        this.validateCodeET = validateCodeET;
    }

    public Button getEnterBT() {
        return enterBT;
    }

    public void setEnterBT(Button enterBT) {
        this.enterBT = enterBT;
    }

}

ExampleViewHolder中使用了XUtil框架的注解

3、BaseBusiness

package com.winway.collectiondata.base;

import com.lidroid.xutils.ViewUtils;

import android.app.Activity;
import android.content.Intent;

/**
 * 基本业务类
 * 
 * @author mr-lao
 *
 */
public abstract class BaseBusiness<T> {
    // Activity对象,业务可以用来获得Activity中拥有的功能代码
    protected Activity mActivity;
    // ViewHolder对象,存放业务需要乃至的View控件
    protected T viewHolder;

    public Activity getActivity() {
        return mActivity;
    }

    public void setActivity(Activity mActivity) {
        this.mActivity = mActivity;
    }

    public T getViewHolder() {
        return viewHolder;
    }

    /**
     * 设置ViewHolder对象,并对业务实体进行初始化
     * 
     * @param viewHolder
     */
    public void setViewHolder(T viewHolder) {
        this.viewHolder = viewHolder;
        init();
    }

    /**
     * 注入view和事件
     * 
     * @param activity
     * @param holderClass
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void initBusiness(Activity activity, Class<T> holderClass)
            throws InstantiationException, IllegalAccessException {
        this.viewHolder = holderClass.newInstance();
        initBusiness(activity, this.viewHolder);
    }

    /**
     * 注入view和事件
     * 
     * @param activity
     * @param viewHolder
     */
    public void initBusiness(Activity activity, T viewHolder) {
        this.mActivity = activity;
        // 用xUtil的ViewInject功能初始化viewholder对象
        this.viewHolder = viewHolder;
        ViewUtils.inject(this.viewHolder, activity);
        ViewUtils.inject(this, activity);
        // 回调初始化方法
        init();
    }

    /**
     * 当Activity调用setViewHolder或initBusiness方法 时,会调用init()方法。
     * 子类通过实现init()方法来初始化自身的一些属性和数据,init()方法是业务类的入口方法。
     */
    public abstract void init();

    // 申明一些与Activity中请用的方法名字相同的方法

    /**
     * 处理从Activity跳到另外一个Activity返回来的数据(需要用到的话,子类重写此方法即可,不需要用到的话,请忽略)
     * 
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

    }

    /**
     * 获得从另一个Activity跳转到此Activity的意图对象,借此,获得跳转Activity带来的数据
     * 
     * @return
     */
    public Intent getIntent() {
        return mActivity.getIntent();
    }

    /**
     * 请在Activity的onDestroy()方法中调用
     */
    public void onDestroy() {

    }

    /**
     * 请在Activity的onResume()方法中调用
     */
    public void onResume() {

    }

    /**
     * 请在Activity的onPause()方法中调用
     */
    public void onPause() {

    }

    /**
     * 请在Activity的onStop()方法中调用
     */
    public void onStop() {

    }

    /**
     * 请在Activity的onRestart()方法中调用
     */
    public void onRestart() {

    }
}

4、activity_example.xml (布局)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#326373"
        android:gravity="center"
        android:padding="4dp"
        android:text="Title"
        android:textColor="#FFFFFF" />

    <EditText
        android:id="@+id/username"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:padding="5dp" />

    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:padding="5dp"
        android:password="true" />

    <EditText
        android:id="@+id/code"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:padding="5dp"
        android:phoneNumber="true" />

    <Button
        android:id="@+id/login"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:text="登陆" />

</LinearLayout>

5、ExampleActivity

package com.winway.collectiondata.activity;

import com.winway.collectiondata.R;
import com.winway.collectiondata.business.example.ExampleBusiness;
import com.winway.collectiondata.viewholder.ExampleViewHolder;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;

/**
 * 
 * @author mr-lao
 *
 */

@SuppressLint("CutPasteId")
public class ExampleActivity extends Activity {
    private ExampleBusiness exampleBSS;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);
        initExampleBBS();
    }

    private void initExampleBBS() {
        exampleBSS = new ExampleBusiness();
        try {
            exampleBSS.initBusiness(this, ExampleViewHolder.class);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        exampleBSS.onDestroy();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        exampleBSS.onResume();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        exampleBSS.onPause();
    }

    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        exampleBSS.onStop();
    }

    @Override
    protected void onRestart() {
        // TODO Auto-generated method stub
        super.onRestart();
        exampleBSS.onRestart();
    }
}

6、ExampleBusiness

package com.winway.collectiondata.business.example;

import com.lidroid.xutils.view.annotation.event.OnClick;
import com.winway.collectiondata.R;
import com.winway.collectiondata.base.BaseBusiness;
import com.winway.collectiondata.viewholder.ExampleViewHolder;

import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

/**
 * 例子业务处理类
 * @author mr-lao
 *
 */
public class ExampleBusiness extends BaseBusiness<ExampleViewHolder> {
    @Override
    public void init() {
        // 给按纽注册监听器
        viewHolder.enterBT.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = viewHolder.usernameET.getText().toString();
                String password = viewHolder.passwordET.getText().toString();
                String code = viewHolder.validateCodeET.getText().toString();
                if (TextUtils.isEmpty(userName)) {
                    Toast.makeText(getActivity(), "用户名不能为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                if (TextUtils.isEmpty(password)) {
                    Toast.makeText(getActivity(), "密码不能为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                if (TextUtils.isEmpty(code)) {
                    Toast.makeText(getActivity(), "验证码不能为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                Toast.makeText(getActivity(),
                        "username=" + userName + ",password=" + password + ",code=" + code,
                        Toast.LENGTH_LONG).show();
                boolean ll = login(userName, password, code);
                if (ll) {
                    Toast.makeText(mActivity, "登陆成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(mActivity, "登陆失败", Toast.LENGTH_SHORT).show();
                }
            }
        });
        // 设置标题
        viewHolder.titleTV.setText("ExampleBusiness");
    }

    /**
     * 模拟登陆
     * @param username
     * @param password
     * @param code
     * @return
     */
    private boolean login(String username, String password, String code) {
        if (!"admin".equals(username)) {
            Toast.makeText(mActivity, "用户名错误,请填写admin", Toast.LENGTH_SHORT).show();
            return false;
        }
        if (!"password".equals(password)) {
            Toast.makeText(mActivity, "密码错误,请填写password", Toast.LENGTH_SHORT).show();
            return false;
        }
        if (!"123456".equals(code)) {
            Toast.makeText(mActivity, "验证码错误,请填写123456", Toast.LENGTH_SHORT).show();
            return false;
        }
        return true;
    }

    @OnClick(R.id.title)
    public void clickTitle(View view) {
        Toast.makeText(getActivity(), "点击了标题。。。。。。。", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDestroy() {
        Log.i("info", "ExampleBusiness onDestroy");
    }

    @Override
    public void onPause() {
        Log.i("info", "ExampleBusiness onPause");
    }

    @Override
    public void onStop() {
        Log.i("info", "ExampleBusiness onStop");
    }

    @Override
    public void onResume() {
        Log.i("info", "ExampleBusiness onResume");
    }

}

解读:
传统的安卓开发,造成Activity与UI以及业务代码高度耦合,是由于View控件的不独立,View的不独立造成业务代码的不独立。
CVB模式首先是将View从Activity中抽取出来,存放于ViewHolder容器中,使得View从Activity中独立出来。
其次是将Business当成一个普通的Java类,Activity中把ViewHolder对象传递给Business对象即可,同时,Activity也把自身传递给Business,使得Business不仅可以操作View,也可以拥有Activity所拥有的功能。

源码下载:http://download.csdn.net/detail/qq_25929547/9707400

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值