1、BroadCastReceiver:广播接收者
Android中:系统在运行过程中,会产生会多事件,那么某些事件产生时,比如:电量改变、收发短信、拨打电话、屏幕解锁、开机,系统会发送广播,只要应用程序接收到这条广播,就知道系统发生了相应的事件,从而执行相应的代码。使用广播接收者,就可以收听广播。
创建BroadCastReceiver 广播接收者:
第一步: 创建一个java类 继承extends broadcastreceiver; ( android.content.BroadcastReceiver)
第二步:配置清单文件: 在清单文件中定义recevier节点,定义name属性,指定广播接收者java类的全类名。
<receiver android:name="com.zh.ipdailor.CallRecevier" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
在intent-filter的节点中,指定action子节点,action的值必须跟要接受的广播中的action匹配,比如,如果要接受打电话广播,
那么action的值必须指定为 intent 意图对象。 打电话 New_OUTGOING_CALL;<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
- 因为打电话广播中所包含的action,就是”android.intent.action.NEW_OUTGOING_CALL”,所以我们定义广播接收者时,
action必须与其匹配,才能收到这条广播
4、设置权限;
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
- 即便广播接收者所在进程已经被关闭,当系统发出的广播中的action跟该广播接收者的action匹配时,系统会启动该广播接收者所在的进程,
并把广播发给该广播接收者
demo1 :
- 因为打电话广播中所包含的action,就是”android.intent.action.NEW_OUTGOING_CALL”,所以我们定义广播接收者时,
定义一个类继承广播接收者,在onReceive方法中就可以接收到打电话应用发布的广播。
package com.zh.ipdailor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class CallRecevier extends BroadcastReceiver {
//接收到广播时会调用。
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.out.println("电话已经收到!!!!");
}
}
打电话广播中会携带号码(也就是数据)接收者怎样获得该数据呢?
getResultData(); 返回值就是String 类型的 该值就是广播携带的数据。
注:SharedPreferences 轻量级的存储
将输入框中的数据储存在本地方法:
EditText et = (EditText) findViewById(R.id.et);
getSharedPreferences 方法对象是上下文Context
SharedPreferences sp =getSharedPreferences(name, mode) // name 文件的名字 mode 一般是私有MODE_PRIVATE
Editor ed = sp.edit();
ed.putString("ipName","et.getText().toString"); // ed.putString(key, value)
ed.commit(); //注意要提交。
finish(); //将 该Acativity结束掉。
在广播接收者中读取存在内存中的ip号码,然后添加到广播携带的数据的前面。 最后将数据再放回到广播中。
package com.zh.ipdailor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
public class CallRecevier extends BroadcastReceiver {
//接收到广播时会调用。
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//在打电话广播中会携带数据,通过getResultData 获得
String number =getResultData();
//将储存在SharedPreferences 中的数据取出
if(number.startsWith("0"))//判断一下 加入拨打号码的头带零 自动启动Ip拨号器
{
SharedPreferences sp = context.getSharedPreferences("ip", Context.MODE_PRIVATE);
String ipName = sp.getString("ipName", "");
System.out.println("ipName"+ipName);
//把ip号码拼接在 拨的号码的前面
number= ipName+number;
//将拼接后的数据放回到广播中。
setResultData(number);
}
}
}
拨号盘的数据被广播携带着(非intent传递),数据在传往打电话的应用中被广播接收者截获并修改了里面的数据。
demo2:
短信防火墙
也是利用广播,短信广播。 //android.Provider.Telephoy.SMS_RECEIVIED
创建一个java类继承BroadCastReceiver广播接收者;
配置清单文件,添加receiver节点与activity同级节点。
<receiver android:name="com.zh.msglanjie.MsgRecevier" >
<intent-filter>//意图过滤器中的action必须要和短信广播的action一致。
<action android:name="android.provider.Telephony.SMS_RECEIVED" /> //短信广播的action
</intent-filter>
</receiver>
emulator control 模拟器控制器。
The Emulator Control tab, shown in Figure 1, is no longer supported. Use the Android Emulator for these features. //Google官网。
在extended controls 中有。
这里也需要添加权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/> 接收信息的权限。
从短信中拿取内容,不像打电话的广播直接getResultData得到的是字符串String 但短信的内容太多了。
广播的内容也可以用意图发的,在短信中内容封装在intent对象中。
pdu: 协议数据单元.
系统发送短信广播时,是怎么把短信内容存入广播的,我们就只能怎么取出来
* 如果短信过长,那么发送时会拆分成多条短信发送,那么短信广播中就会包含多条短信
* 4.0之后,广播接收者所在进程如果从来没启动过,那么广播接收者不会生效
* 4.0之后,如果系统自动关闭广播接收者所在进程,在广播中的action跟该广播接收者的action匹配时,系统会启动该广播接收者所在的进程,但是如果是用户手动关闭该进程,
那么该进程会进入冻结状态,再也不会启动了,直到用户下一次手动启动该进程
取短信的方式:
//获取短信的内容。短信的内容封装在intent中的。
Bundle bundle= intent.getExtras();
//以pdus为键取出 一个object数组, 数组中的每一个元素都是一条短信。
Object[] objects= (Object[]) bundle.get("pdus");
for(Object object: objects )
{ //通过协议数据单元构造短信。
if (sms.getOriginatingAddress().equals("138438")) {
abortBroadcast();// 拦截广播
// SmsManager.getDefault().sendTextMessage("138438", null,
// "你是个好人", null, null);
System.out.println(sms.getMessageBody());
}
短信应用收的是短信广播。
短信防火墙设置的时候,要优先于短信应用之前收到短信,要不拦截不到短信。abortBroadCast(); 拦截广播。
优先级的区间是-1000-1000 设置优先级在清单文件中将短信防火墙的priority(优先级) 、intent-filter android:priority=”1000”>
<receiver android:name="com.zh.msglanjie.MsgRecevier" >
<intent-filter android:priority="1000"> // 设置广播接收者的优先级。 此时优先级最高。
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
4.0之后如果短信拦截没有在系统上加载过,快捷图标删除后是不能正常运行的。也就是广播接收者至少要在系统上运行一次。
resource —— values——Strings——可以更改app的名字 。将activity 下面的意图过滤器删除后广播接收者,就不会再前台显示,此时如果把进程即使杀死(不是用户自行关闭)当有短信广播时进程会自行启动。当用户手动关闭时广播接收者处于冻结状态只有下次被启动时才会被打开。
SD卡监控:一个广播接收者接收多条广播 只需在一个Receiver节点下添加多个action即可。
SD卡广播接收者 中的intent-filter 要与sd卡广播的内容要匹配包括 action和data节点
4.3没办法卸载sdk卡可以在2.3模拟。
<action android:name="android.intent.action.MEDIA_MOUNTED"/> //sd卡挂载状态。
<action android:name="android.intent.action.MEDIA_REMOVED"/>// sd卡拔出状态。
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/> //sd卡未挂载。
<data android:scheme="file"/> //sd卡广播中的scheme 就是file 要与其匹配。
android.content.BroadcastReceiver
package com.zh.sdlistenter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class SdListenter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// 监控判断sd卡的状态
String action = intent.getAction();
if ("android.intent.action.MEDIA_MOUNTED".equals(action)) {
Toast.makeText(context, "sd卡已经加载成功", 0).show();
}
if ("android.intent.action.MEDIA_REMOVED".equals(action)) {
Toast.makeText(context, "sd卡已拔出", 0).show();
}
if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
Toast.makeText(context, "sd卡未加载不可用", 0).show();
}
}
}
开机启动BroadCastReceiver:
BootReceiver:开机启动广播接收者 extends BroadCastReceiver
清单文件配置: intent-filter Boot_completed.
使Android机器返回键不能用可以禁用onBackPressed。
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
// super.onBackPressed(); //该应用的返回键不能用。
}
}
<receiver android:name="com.zh.jiechi.BootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
广播接收者属于后台运行,要显示在广播接收者中定义显示的activity,需要定义flag 新的界面任务栈;
package com.zh.jiechi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.view.ViewDebug.FlagToString;
import android.widget.Toast;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//开机启动设定界面。
Intent it = new Intent(context, MainActivity.class);
//此flag如不设定会导致开机时应用崩溃。 新的界面栈。
it.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(it);
}
}
监控手机应用状态:
携带一个data
清单文件
<receiver android:name="com.zh.applistener.AppStatusReceiver">
<intent-filter >
<action android:name="android.intent.action.PACKAGE_ADDED"/> //安装应用
<action android:name="android.intent.action.PACKAGE_REMOVED"/> //删除应用
<action android:name="android.intent.action.PACKAGE_REPLACED"/> //replaced 更新
<data android:scheme="package"/> //通过这个数据来告诉用户哪个应用被删了 和更新了。
</intent-filter>
</receiver>
这个更新 状态的实现可是改变一下或加个空格等操作然后保存应用,加载到模拟器:模拟器实现的过程是先被卸载,后安装,然后显示更新了。
自定义广播:
package com.zh.selfdefine;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View v){
Intent intent = new Intent();
intent.setAction("com.zh.zdy"); //这里设置的action和接收端要保持一致。
//发送自定义广播、
sendBroadcast(intent);
}
}
接收上面自定义的广播;
的清单文件设置:
<receiver android:name="com.zh.zdyreceiver.SelfDefineReceiver" >
<intent-filter>
<action android:name="com.zh.zdy" />
</intent-filter>
</receiver>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
广播的分类:
无序广播:
所有与广播中的action匹配的广播接收者都可以收到这条广播,并且是没有先后顺序,视为同时收到。
有序广播: 优先级控制其先后顺序;
所有与广播中的action匹配的广播接收者都可以收到这条广播,但是是有先后顺序的,按照广播接收者的优先级排序。
有序广播:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View v){
Intent intent = new Intent();
intent.setAction("com.zh.fdm");
//发送有序广播 resultReceiver 结果接收者 不需要在清单文件中设置,这个广播接收者只接收该条广播,并且是最后一个接收到该广播的
// 并且一定能收到该广播。
sendOrderedBroadcast(intent, null, new MyReceiver(), null, 0, "每人发100斤大米", null);
}
有序广播接收者的清单文件设置:
<receiver android:name="com.zh.local.Sheng" >
<intent-filter android:priority="1000" > 设置优先级
<action android:name="com.zh.fdm" />
</intent-filter>
</receiver>
<receiver android:name="com.zh.local.Shizf" >
<intent-filter android:priority="500" >
<action android:name="com.zh.fdm" />
</intent-filter>
</receiver>
<receiver android:name="com.zh.local.Xianzf" >
<intent-filter android:priority="200" >
<action android:name="com.zh.fdm" />
</intent-filter>
</receiver>
有序广播由于有先后顺序,数据可以被修改,拦截; 像打电话,发短信都属于有序广播。
有序广播接收者:
public class Sheng extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//得到广播中的内容
String text=getResultData();
System.out.println("省政府收到的文件"+text); //将原来的数据改变。
setResultData("每人发80斤大米"); //这个方法对于无序广播是无效的。
}
}
有序广播有一个最终广播接收者:
最终接收者,最后一个并且一定能收到的,打电话的应用就是一个有序广播而且是被定义最终接收者。
sendOrderedBroadcast(intent, null, new MyReceiver(), null, 0, "每人发100斤大米", null);
}
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String text = getResultData();
System.out.println("反贪局"+text);
}