代码改变世界

Android四大组件之BroadcastReceiver

2015-11-09 21:16  叫我小陈  阅读(266)  评论(0编辑  收藏  举报
 

广播接收者
   现实中:电台要发布消息,通过广播把消息广播出去,使用收音机,就可以收听广播,得知这条消息
  Android中:系统在运行过程中,会产生会多事件,那么某些事件产生时,比如:电量改变、收发短信、拨打电话、屏幕解锁、开机,系统会发送广播,只要应用程序接收到这条广播,就知道系统发生了相应的事件,从而执行相应的代码。使用广播接收者,就可以收听广播


 

创建广播接收者

   1. 定义java类继承BroadcastReceiver

   2. 在清单文件中定义receiver节点,定义name属性,指定广播接收者java类的全类名

     3. 在intent-filter的节点中,指定action子节点,action的值必须跟要接受的广播中的action匹配,比如,如果要接受打电话广播,那么action的值必须指定为

     <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>

  * 因为打电话广播中所包含的action,就是"android.intent.action.NEW_OUTGOING_CALL",所以我们定义广播接收者时,
  action必须与其匹配,才能收到这条广播
  * 即便广播接收者所在进程已经被关闭,当系统发出的广播中的action跟该广播接收者的action匹配时,系统会启动该广播接收者所在的进程,
  并把广播发给该广播接收者


简单案例体现广播接受者

  ip拨号器

  需求:简单判断如果拨打的电话以0开头,视为外地号码,则在原号码前添加17951ip线路,使新号码以17951+原号码的形式拨出去

  原理:拨号盘把号码通过广播将数据传递给打电话应用,拨号盘发了一条广播,广播中带着号码数据,拨号盘发的广播在去往打电话的过程中被我们写的项目截下来了,做了修改之后,最后打电话收到的广播中的电话号码是做了修改的号码

  

输入ip号 点击保存,再下次打电话的时候,就会在有0开头的号码前自动添加上ip号码

 

//在MainActivity 的click方法中,先拿到ip地址,同sharePreferences方法将输入框中的ip地址拿到并且保存到内存中
 public void click(View v) {
    	EditText et = (EditText) findViewById(R.id.et);
    	String ip = et.getText().toString();
    	SharedPreferences sp = getSharedPreferences("ip", MODE_PRIVATE);
    	sp.edit().putString("ip", ip).commit();
    }

  

public class ipService extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
            //拿到广播中的数据
		String number = getResultData();
		if(number.startsWith("0")) {
                 //对数据判断之后,取出内存中的数据
			SharedPreferences sp = context.getSharedPreferences("ip", context.MODE_PRIVATE);
			String ip =  sp.getString("ip", "");
			number = ip + number;
//将修改后的号码重新放到广播中
			setResultData(number);
		}
	}
}

  

//在写广播接收者方法时要做如下的配置 在清单文件中的注册如下
<receiver android:name="com.example.ip.ipService">
            <intent-filter >
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
            </intent-filter>
        </receiver>


//同时接收打电话广播需要以下权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

  案例二 短信防火墙

    正常的短信防火墙会从数据库中查询到,要拦截到哪些号码,在下面的案例中我们写死

    

 
//接收短信广播的action是android.provider.Telephony.SMS_RECEIVED
//如果要拦截断线 还需要设置短信接收者的优先级<intent-filter android:priority="1000" >
<receiver android:name="com.example.message.smsMessage">
           <intent-filter android:priority="1000" >
               <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
           </intent-filter>
       </receiver>

  

public class smsMessage extends BroadcastReceiver {
//系统创建广播时,把短信存放到一个数组,然后把数据以pdus为key存入bundle,再把bundle存入intent
	public void onReceive(Context context, Intent intent) {
		
		Bundle bundle = intent.getExtras();
		Object[] objects  = (Object[]) bundle.get("pdus");
		for (Object ob : objects) {
			SmsMessage sms = SmsMessage.createFromPdu((byte[]) ob);
			if((sms.getOriginatingAddress()).equals("123")){;
				abortBroadcast();
			}
		}
	}
}

  System.out.println(sms.getMessageBody());//可以得到短信的内容

* 4.0以后广播接收者安装以后必须手动启动一次,否则不生效
* 4.0以后广播接收者如果被手动关闭,就不会再启动了


 

我可以通过广播来监听sd卡的状态

//清单文件中定义广播接收者接收的类型,监听SD卡常见的三种状态,所以广播接收者需要接收三种广播

	 <receiver android:name="com.itheima.sdcradlistener.SDCardReceiver">
            <intent-filter >
                <action android:name="android.intent.action.MEDIA_MOUNTED"/>
                <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
                <action android:name="android.intent.action.MEDIA_REMOVED"/>
                <data android:scheme="file"/>
            </intent-filter>
        </receiver>

  

public class SDStatusReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		//判断收到的到底是什么广播
		String action = intent.getAction();
		if("android.intent.action.MEDIA_MOUNTED".equals(action)){
			Toast.makeText(context, "SD卡可用", 0).show();
		}
		else if("android.intent.action.MEDIA_REMOVED".equals(action)){
			Toast.makeText(context, "SD卡拔出", 0).show();
		}
		else if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){
			Toast.makeText(context, "SD卡不可用", 0).show();
		}
	}
}

  

 


 

通过广播接受者 ,实现开机自动启动

 <receiver android:name="com.example.shoujileisuo.service">
            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

//权限
 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

  

public class service extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
//设置意图对象,开机重启界面
		Intent it = new Intent(context, MainActivity.class);
//广播接收者的启动并不会创建任务栈,没有任务栈就无法启动activity,手动创建设置新任务栈
		it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(it);
	}
}

  


监听应用的安装、卸载、更新

原理:应用在安装卸载更新时,系统会发送广播,广播里会携带应用的包名

<receiver android:name="com.example.jianting.receive">
                <intent-filter >
                <action android:name="android.intent.action.PACKAGE_ADDED"/>
                <action android:name="android.intent.action.PACKAGE_REPLACED"/>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package"/>
            </intent-filter>
        </receiver>

  

public class receive extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		Uri uri = intent.getData();
		
		if("android.intent.action.PACKAGE_ADDED".equals(action)) {
			Toast.makeText(context, uri.toString() + "被安装了", 0).show();
		}
		if("android.intent.action.PACKAGE_REMOVED".equals(action)) {
			Toast.makeText(context, uri.toString() + "被卸载了", 0).show();
			}
		if("android.intent.action.PACKAGE_REPLACED".equals(action)){
			Toast.makeText(context, uri.toString() + "被升级了", 0).show();
		}
			
		}

	}

  


 

发送自定义广播

//发送广播端
public void click(View v) { Intent intent = new Intent(); intent.setAction("com.example.zdy"); sendBroadcast(intent); }
//接收广播端
//做清单文件注册

<receiver android:name="com.example.receive.receive">
  <intent-filter >
    <action android:name="com.example.zdy"/>
  </intent-filter>
</receiver>

  


 

发送有序广播

广播的两种类型
   无序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,并且是没有先后顺序(同时收到)
   有序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,但是会按照广播接收者的优先级来决定接收的先后顺序
   优先级的定义:-1000~1000
  最终接收者:所有广播接收者都接收到广播之后,它才接收,并且一定会接收
   abortBroadCast:阻止其他接收者接收这条广播,类似拦截,只有有序广播可以被拦截

 public void click(View v) {
    	Intent intent = new Intent();
    	intent.setAction("com.example.fdm");
    	sendOrderedBroadcast(intent, null,  new resultReceiver(),null , 0, "发1000", null);
    }
    class resultReceiver extends BroadcastReceiver{

		@Override
		public void onReceive(Context context, Intent intent) {
			String rice = getResultData();
			Toast.makeText(context, rice, 0).show();
			
		}
    	
    }

  

<receiver android:name="com.itheima.local.ShengZF">
            <intent-filter android:priority="1000">
                <action android:name="com.itheima.fdm"/>
            </intent-filter>
        </receiver>
        <receiver android:name="com.itheima.local.ShiZF">
            <intent-filter android:priority="800">
                <action android:name="com.itheima.fdm"/>
            </intent-filter>
        </receiver>
        <receiver android:name="com.itheima.local.XianZF">
            <intent-filter android:priority="600">
                <action android:name="com.itheima.fdm"/>
            </intent-filter>
        </receiver>

  

public class ShengZF extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		String text = getResultData();
		System.out.println("省政府收到文件:" + text);
		setResultData("每人发80斤大米");
	}

}

  

public class ShiZF extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		String text = getResultData();
		System.out.println("市政府收到文件:" + text);
		abortBroadcast();
	}

}

  

public class XianZF extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		String text = getResultData();
		System.out.println("县政府收到文件:" + text);
	}

}