Android设计模式之观察者模式

Android设计模式之观察者模式

观察者模式(Observer Pattern)

  • 定义对象间的一种一个(Observable)对多(Observer)的依赖关系,当一个对象的状态发送改变时,所以依赖于它的对象都得到通知并被自动更新。

  • 当然,MVC只是Observer模式的一个实例。

  • Observer模式要解决的问题为:建立一个一(Observable)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer模式就是解决了这一个问题。

  • 因此我们知道,观察者模式中主要有观察者和被观察者2个对象,而在观察模式中Observable表示被观察者,由于这个对象是一个抽象类,所以只能被继承。而Observer表示观察者,它并不是一个类而是一个接口,所以观察者可以有多个,实现了该接口的类都属于观察者。 当然有人会问既然被观察者是一个抽象类而观察者是一个接口,那么是否有一个类即继承Observable类又实现Observer接口呢,这个自然可以,观察者当然也可以同时是被观察者,被观察者同样可以是观察者,在这里完全不冲突。

  • 当某一个我们需要被观察的对象继承自Observable类时,就表示该类可以被很多观察者(实现了Observer)观察,其实意思就是说这个对象也就是被观察者“上电视了”,电视前的你也就是观察者可以看,(对象发生变化)电视里被观察者做了别的动作,那么电视前的所有人看到的也就变了,在同一时间改变所有观众看到的画面。

观察者模式的适用性:

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面,将这两者封装成独立的对象中以使它们可以各自独立的改变和服用
  2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
  3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁

观察者模式的参与者:

  1. Observable(目标也叫被观察者)
    • 目标知道它的观察者,可以有任意多个观察者观察同一个目标
    • 提供注册和删除观察者对象的接口
  2. Observer(观察者)
    • 为那些在目标发生改变时需获得通知的对象定义个更新的接口
  3. ConcreteObservable(具体目标)
    • 将有关状态存入各ConcreteObserver对象
    • 当它的状态发送改变时,向它的各个观察者发出通知
  4. ConcreteObserver(具体观察者)
    • 维护一个指向ConcreteObserver对象的引用
    • 存储有关状态,这些状态应与目标的状态保持一致
    • 实现Observer的更新接口是自身状态与目标的状态保持一致

下面我们用一个例子来展示Android观察者模式

例如:MyPerson是被观察者:

package com.shijiacheng.observerpattern;

import java.util.Observable;

public class MyPerson extends Observable {

    private String name;
    private int age;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        setChanged();
        notifyObservers();
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        setChanged();
        notifyObservers();
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
        setChanged();
        notifyObservers();
    }

    @Override
    public String toString() {
        return "MyPerson [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }
}
  • 注意到:setChanged();notifyObservers();多了这两句调用,通过setChanged();告知数据改变,通过notifyObservers();发送信号通知观察者。

MyObserver是观察者:

package com.shijiacheng.observerpattern;

import java.util.Observable;
import java.util.Observer;

public class MyObserver implements Observer {

    private int id;
    private MyPerson myPerson;

    public MyObserver(int id) {
        System.out.println("我是观察者---->" + id);
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public MyPerson getMyPerson() {
        return myPerson;
    }

    public void setMyPerson(MyPerson myPerson) {
        this.myPerson = myPerson;
    }

    @Override
    public void update(Observable observable, Object data) {
        System.out.println("观察者---->" + id + "得到更新");
        this.myPerson = (MyPerson) observable;
        System.out.println(((MyPerson) observable).toString());
    }

}
  • 这里我们看到,实现了Observer,只有一个update方法,那么这个方法什么时候被调用呢,很显然,在上面我们有通知的信号,那么这里就是接受到信号后执行的动作。

MainActivity主函数:

package com.shijiacheng.observerpattern;

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

import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;

public class MainActivity extends ListActivity {

    private Button btnAddObserver;
    private Button btnChangeData;
    private MyPerson observable;
    private MyObserver myObserver;
    private List<MyObserver> myObservers;
    private ListView listview;

    private int i;

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            MyListAdapter myListAdapter = new MyListAdapter(MainActivity.this,
                    myObservers);
            listview.setAdapter(myListAdapter);

        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnAddObserver = (Button) findViewById(R.id.btn_add_observer);
        btnChangeData = (Button) findViewById(R.id.btn_change_data);
        listview = getListView();

        observable = new MyPerson();
        myObservers = new ArrayList<MyObserver>();

        btnAddObserver.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                myObserver = new MyObserver(i);
                i++;
                observable.addObserver(myObserver);
                myObservers.add(myObserver);
                handler.sendEmptyMessage(0);
            }
        });

        btnChangeData.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                observable.setName("a" + i);
                observable.setAge(10 + i);
                observable.setSex("男" + i);
                handler.sendEmptyMessage(0);
            }
        });

    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        observable.deleteObserver(myObserver);
    }
}
  • btn_add_observer这个button是用来添加观察者的,而我们看到myObservers.add(myObserver);这样一句,它的意思就是为被观察者添加观察者的。btn_change_data这个button用来改变数据用于测试。

最后,看一下实例的效果图和输出log:

  • 当点击一次“添加观察者”:

《Android设计模式之观察者模式》

《Android设计模式之观察者模式》

  • 点击一次“改变数据”:

《Android设计模式之观察者模式》

《Android设计模式之观察者模式》

  • 然后点击三次“添加观察者”:

《Android设计模式之观察者模式》

  • 点击三次“改变数据”:

《Android设计模式之观察者模式》

《Android设计模式之观察者模式》

源码下载地址:http://download.csdn.net/detail/u012771445/9367896

下面我们展示一个在Android应用开发中应用观察者模式的实例:

Android 项目开发实战:短信验证码自动填写

《Android设计模式之观察者模式》

ContentObserver

  • 内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当 ContentObserver 所观察的Uri发生变化时,便会触发它。

观察特定Uri的步骤如下:

  1. 创建我们特定的 ContentObserver 派生类,必须重载父类构造方法,必须重载 onChange() 方法去处理回调后的功能实现。
  2. 利用 context.getContentResolover() 获得 ContentResolove 对象,接着调用 registerContentObserver() 方法去注册内容观察者。
  3. 由于 ContentObserver 的生命周期不同步于 Activity 和 Service 等,因此,在不需要时,需要手动的调用 unregisterContentObserver() 去取消注册。

SmsObserver.java

package com.shijiacheng.verificationcode;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;

public class SmsObserver extends ContentObserver {

    private Context mContext;
    private Handler mHandler;

    public SmsObserver(Context context, Handler handler) {
        super(handler);
        mContext = context;
        mHandler = handler;
    }

    /**
     * 接收到短信时调用此方法
     */
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);

        Log.d("DEBUG", "SMS has changed!");
        Log.d("DEBUG", uri.toString());

        if (uri.toString().equals("content://sms/raw")) {
            return;
        }

        Uri inboxUri = Uri.parse("content://sms/inbox");
        Cursor cursor = mContext.getContentResolver().query(inboxUri, null,
                null, null, "date desc");
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                String address = cursor.getString(cursor
                        .getColumnIndex("address"));
                String body = cursor.getString(cursor.getColumnIndex("body"));
                Log.d("DEBUG", "发件人为:" + address + " " + "短信内容为:" + body);

                // if (!address.equals("你的公司的手机号")) {
                // return;
                // }

                Pattern pattern = Pattern.compile("(\\d{6})");//正则表达式
                Matcher matcher = pattern.matcher(body);
                if (matcher.find()) {
                    String code = matcher.group(0);
                    Log.d("DEBUG", "code is" + code);

                    mHandler.obtainMessage(MainActivity.MSG_RECEIVED_CODE, code)
                            .sendToTarget();
                }
            }
        }

    }

}

MainActivity.java

package com.shijiacheng.verificationcode;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.widget.EditText;

public class MainActivity extends Activity {
    public static final int MSG_RECEIVED_CODE = 1;

    private EditText etVerficationCode;

    private SmsObserver mObserver;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            if (msg.what == MSG_RECEIVED_CODE) {
                String code = (String) msg.obj;
                etVerficationCode.setText(code);
            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        etVerficationCode = (EditText) findViewById(R.id.et_verification_code);

        mObserver = new SmsObserver(MainActivity.this, mHandler);
        Uri uri = Uri.parse("content://sms");
        getContentResolver().registerContentObserver(uri, true, mObserver);
    }

    @Override
    protected void onPause() {
        super.onPause();
        getContentResolver().unregisterContentObserver(mObserver);
    }
}

源码下载地址:http://download.csdn.net/detail/u012771445/9367900

这是我最近在公司项目中接触到的Android观察者模式的一点心得,能力有限,可能存在错误和不足的地方,欢迎大家指正,希望我的经验能够帮到你。

欢迎大家关注我的博客:http://blog.csdn.net/u012771445

Github:https://gitub.com/shijiacheng

    原文作者:认真的小成
    原文地址: http://www.cnblogs.com/shijiacheng/p/5059067.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞