设计模式(十九)----- 观察者模式(Observer)----(Android版)

      观察者模式(Observer)在Android中的应用也是比较普遍和重要的,下面,我们总合几个例子从应用的角度来谈一谈:

第一部分:ContentObserver

Class Overview:
      Receives call backs for changes to content. Must be implemented by objects which are added to a ContentObservable

     ContentObserver-----内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理, 非常明显,ContentObserver对应于观察者模式(Observer)中Observer(观察者),


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


下面有一个Demo,有两个不同的ContentObserver派生类,如下:

1、用来观察系统是否改变了飞行模式状态,
    PS: 大家可以去SDK中查看该类:android.provider.Settings.System。该类封装了对设置模块下所有值的存取,比如:飞行模式状态、蓝牙状态、屏幕亮度值等,并且提供了相应的Uri。
2、观察系统的短信息数据发生了变化。当监听到短信数据发生变化时,查询所有已发送的短信并且显示出来。

短信的Uri共有一下几种:
content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱 (正在发送的信息)
content://sms/failed 发送失败
content://sms/queued 待发送列表 (比如开启飞行模式后,该短信就在待发送列表里)

1、 观察飞行模式状态的ContentObserver派生类,AirplaneContentObserver.java

package com.qin.contentobserver;

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.*;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;


//用来观察system表里飞行模式所在行是否发生变化 , “行”内容观察者
public class AirplaneContentObserver extends ContentObserver {

	private static String TAG = "AirplaneContentObserver" ;	
	private static int MSG_AIRPLANE = 1 ;	
	private Context mContext;    
        private Handler mHandler ;  //此Handler用来更新UI线程
    
	public AirplaneContentObserver(Context context, Handler handler) {
		super(handler);
		mContext = context;
		mHandler = handler ;
	}

	/**
	 * 当所监听的Uri发生改变时,就会回调此方法
	 * 
	 * @param selfChange 此值意义不大 一般情况下该回调值false
	 */
	@Override
	public void onChange(boolean selfChange) {
        Log.i(TAG, "-------------the airplane mode has changed-------------");
        
	// 系统是否处于飞行模式下
	try {
		int isAirplaneOpen = Settings.System.getInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON);
		Log.i(TAG, " isAirplaneOpen -----> " +isAirplaneOpen) ;
		mHandler.obtainMessage(MSG_AIRPLANE,isAirplaneOpen).sendToTarget() ;
	}
	catch (SettingNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	}

}

2、观察系统里短消息的数据库变化的ContentObserver派生类, SMSContentObserver.java

package com.qin.contentobserver;

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


//用来观察系统里短消息的数据库变化  ”表“内容观察者,只要信息数据库发生变化,都会触发该ContentObserver 派生类
public class SMSContentObserver extends ContentObserver {
    private static String TAG = "SMSContentObserver";	
    private int MSG_OUTBOXCONTENT = 2 ;
    
    private Context mContext  ;
    private Handler mHandler ;   //更新UI线程
	
    public SMSContentObserver(Context context,Handler handler) {
	super(handler);
	mContext = context ;
	mHandler = handler ;
    }
     /**
       * 当所监听的Uri发生改变时,就会回调此方法
       * 
       * @param selfChange  此值意义不大 一般情况下该回调值false
       */
    @Override
    public void onChange(boolean selfChange){
    	Log.i(TAG, "the sms table has changed"); 	
	//查询发件箱里的内容    	
    	Uri outSMSUri = Uri.parse("content://sms/sent") ;
    	
    	Cursor c = mContext.getContentResolver().query(outSMSUri, null, null, null,"date desc");
    	if(c != null){  		
            Log.i(TAG, "the number of send is"+c.getCount()) ;
            StringBuilder sb = new StringBuilder() ;
            //循环遍历
            while(c.moveToNext()){
//        		sb.append("发件人手机号码: "+c.getInt(c.getColumnIndex("address")))
//        		  .append("信息内容: "+c.getInt(c.getColumnIndex("body")))
//        		  .append("是否查看: "+c.getInt(c.getColumnIndex("read"))) 
//        		  .append("发送时间: "+c.getInt(c.getColumnIndex("date")))
//        		  .append("\n");
        	 sb.append("发件人手机号码: "+c.getInt(c.getColumnIndex("address")))
      		   .append("信息内容: "+c.getString(c.getColumnIndex("body")))
      		   .append("\n");
        	}
        	c.close();       	
        	mHandler.obtainMessage(MSG_OUTBOXCONTENT, sb.toString()).sendToTarget();       	
    	}
	}
	
}

3、主工程逻辑为 MainActivity.java,对短消息的观察Uri,通过测试我发现只能监听此Uri “content://sms” (等同于"content://sms/"),而不能监听其他的Uri,比如"content://sms/outbox"等。

package com.qin.contentobserver;

import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.*;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView tvAirplane;
	private EditText etSmsoutbox;
	// Message 类型值
	private static final int MSG_AIRPLANE = 1;
	private static final int MSG_OUTBOXCONTENT = 2;

	private AirplaneContentObserver airplaneCO;
	private SMSContentObserver smsContentObserver;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		tvAirplane = (TextView) findViewById(R.id.tvAirplane);
		etSmsoutbox = (EditText) findViewById(R.id.smsoutboxContent);

		// 创建两个对象
		airplaneCO = new AirplaneContentObserver(this, mHandler);
		smsContentObserver = new SMSContentObserver(this, mHandler);
		
		//注册内容观察者
		registerContentObservers() ;
	}

	private void registerContentObservers() {
		// 通过调用getUriFor 方法获得 system表里的"飞行模式"所在行的Uri
		Uri airplaneUri = Settings.System.getUriFor(Settings.System.AIRPLANE_MODE_ON);
		// 注册内容观察者
		getContentResolver().registerContentObserver(airplaneUri, false, airplaneCO);
		// ”表“内容观察者 ,通过测试我发现只能监听此Uri -----> content://sms
		// 监听不到其他的Uri 比如说 content://sms/outbox
		Uri smsUri = Uri.parse("content://sms");
		getContentResolver().registerContentObserver(smsUri, true,smsContentObserver);
	}

	private Handler mHandler = new Handler() {

		public void handleMessage(Message msg) {
			
			System.out.println("---mHanlder----");
			switch (msg.what) {
			case MSG_AIRPLANE:
				int isAirplaneOpen = (Integer) msg.obj;
				if (isAirplaneOpen != 0)
					tvAirplane.setText("飞行模式已打开");
				else if (isAirplaneOpen == 0)
					tvAirplane.setText("飞行模式已关闭");
				break;
			case MSG_OUTBOXCONTENT:
				String outbox = (String) msg.obj;
				etSmsoutbox.setText(outbox);
				break;
			default:
				break;
			}
		}
	};
}

Uri airplaneUri = Settings.System.getUriFor(Settings.System.AIRPLANE_MODE_ON)-----------飞行模式的URI为被观察者

Uri smsUri = Uri.parse("content://sms")-----------------------------短信的RRI为被观察者


AirplaneContentObserver --------------------------飞行模式URI的一个具体观察者,我们要重写构造方法和onChange(boolean selfChange),当飞行模式的URI变化时,我们

会自动调用onChange(boolean selfChange)方法

SMSContentObserver -------------------------------短信URI的一个具体观察者,我们要重写构造方法和onChange(boolean selfChange),当短信的URI变化时,我们

会自动调用onChange(boolean selfChange)方法


那么如何让观察者和被观察者联系起来了,就就要靠注册了:

getContentResolver().registerContentObserver(airplaneUri, false, airplaneCO);

getContentResolver().registerContentObserver(smsUri, true,smsContentObserver);








第二部分:Intent--BroadcastReceiver

    Intent----BroadcastReceiver这个组合,就相当于现实社会中的人和人通过电话发短信联系,只要我们要对方的电话号码(Intent在BroadcastReceiver里注册),我们就可以通过向对话的手机号码发送短信(在需要的地方发送Intent),对方就会立刻接到短信从而进行相应的操作(BroadcastReceiver就会自动调用onReceive(Context context, Intent intent)方法从面进行相应的操作)

      下面一个例子是,当我们点击Button时,我们发出一个Intent,然后通过BroadcastReceiver接收到这个Intent,弹出一个Toast信息!

代码清单:

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class TestActivity extends Activity implements OnClickListener {
	
	private static final String TAG = "TestActivity"; 
	public static final String INTENT_ACTION = "INTENT_ACTION";
	
	private static Button myButton = null;
	private MyBroadcastReceiver mReceiver = null;
		

	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        myButton = (Button)findViewById(R.id.myButton);
        myButton.setOnClickListener(this);
        
        /******注册广播*****/
		RegisterRecei();
      
    }

	@Override
	public void onClick(View view) {
		// TODO Auto-generated method stub
		if(view == myButton)
		{
			Intent intent = new Intent();
			intent.setAction(INTENT_ACTION);
			sendBroadcast(intent);
		}
	}
	
	
	/**************广播监听器*************/
	private class MyBroadcastReceiver extends BroadcastReceiver{
		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub			
			final String action = intent.getAction();			
            if (INTENT_ACTION.equals(action)) {               	           	
            	Toast.makeText(getApplicationContext(), "点击了Button", Toast.LENGTH_SHORT).show();               	
            }                       
		}
	};
	
	private void RegisterRecei() {
		// TODO Auto-generated method stub
		mReceiver = new MyBroadcastReceiver();
		final IntentFilter filter = new IntentFilter();	    
	    filter.addAction(INTENT_ACTION);
	    registerReceiver(mReceiver, filter);
	}
	
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		unregisterReceiver(mReceiver);	
	}
	
          
}

可以分析:

ConcreteSubject应该为:

Intent intent = new Intent();
intent.setAction(INTENT_ACTION);

ConcreteObserver:应该为:类 MyBroadcastReceiver

      类MyBroadcastReceiver重写onReceive(Context context, Intent intent)方法,当被观察者内容发送的时候,接收到Intent,然后做相应的处理!


ConcreteSubjectConcreteObserver联系起来的方式为注册:

private void RegisterRecei() {
		// TODO Auto-generated method stub
		mReceiver = new MyBroadcastReceiver();
		final IntentFilter filter = new IntentFilter();	    
	    filter.addAction(INTENT_ACTION);
	    registerReceiver(mReceiver, filter);
	}

unregisterReceiver(mReceiver);	


参考资料

1.http://blog.csdn.net/qinjuning/article/details/7047607

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值