广播

  • 广播的概念

    • 现实:电台通过发送广播发布消息,买个收音机,就能收听
    • Android:系统在产生某个事件时发送广播,应用程序使用广播接收者接收这个广播,就知道系统产生了什么事件。
      Android系统在运行的过程中,会产生很多事件,比如开机、电量改变、收发短信、拨打电话、屏幕解锁

IP拨号器

原理:接收拨打电话的广播,修改广播内携带的电话号码

定义广播接收者接收打电话广播

public class CallReceiver extends BroadcastReceiver {//当广播接收者接收到广播时,此方法会调用@Overridepublic void onReceive(Context context, Intent intent) {//拿到用户拨打的号码String number = getResultData();//修改广播内的号码setResultData("17951" + number);}
}
  • 在清单文件中定义该广播接收者接收的广播类型
<receiver android:name="com.itheima.ipdialer.CallReceiver"><intent-filter ><action android:name="android.intent.action.NEW_OUTGOING_CALL"/></intent-filter></receiver>
  • 接收打电话广播需要权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
  • 即使广播接收者的进程没有启动,当系统发送的广播可以被该接收者接收时,系统会自动启动该接收者所在的进程

案例1:IP拨号器

public class CallReceiver extends BroadcastReceiver {//接收到广播时就会调用@Overridepublic void onReceive(Context context, Intent intent) {//添加IP线路//在打电话广播中,会携带拨打的电话的号码,通过以下代码获取到String number = getResultData();if(number.startsWith("0")){SharedPreferences sp = context.getSharedPreferences("ip", Context.MODE_PRIVATE);String ipNumber = sp.getString("ipNumber", "");//把IP线路号码添加至用户拨打号码的前面number = ipNumber + number;//把新的号码重新放入广播中setResultData(number);abortBroadcast();}        }
}
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){EditText et = (EditText) findViewById(R.id.et);SharedPreferences sp = getSharedPreferences("ip", MODE_PRIVATE);sp.edit().putString("ipNumber", et.getText().toString()).commit();}
}

短信拦截器

系统收到短信时会产生一条广播,广播中包含了短信的号码和内容

  • 定义广播接收者接收短信广播
    public void onReceive(Context context, Intent intent) {//拿到广播里携带的短信内容Bundle bundle = intent.getExtras();Object[] objects = (Object[]) bundle.get("pdus");for(Object ob : objects ){//通过object对象创建一个短信对象SmsMessage sms = SmsMessage.createFromPdu((byte[])ob);System.out.println(sms.getMessageBody());System.out.println(sms.getOriginatingAddress());}
}
  • 系统创建广播时,把短信存放到一个数组,然后把数据以pdus为key存入bundle,再把bundle存入intent
  • 清单文件中配置广播接收者接收的广播类型,注意要设置优先级属性,要保证优先级高于短信应用,才可以实现拦截
<receiver android:name="com.itheima.smslistener.SmsReceiver"><intent-filter android:priority="1000"><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter>
</receiver>
  • 添加权限

<uses-permission android:name=”android.permission.RECEIVE_SMS”/>

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

案例2:短信防火墙

public class SmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//拿到短信的信息//短信内容封装在intent中Bundle bundle = intent.getExtras();//以pdus为键,取出一个object数组,数组中的每一个元素,都是一条短信Object[] objects = (Object[]) bundle.get("pdus");//拿到广播中的所有短信for (Object object : objects) {//通过pdu来构造短信SmsMessage sms = SmsMessage.createFromPdu((byte[])object);if(sms.getOriginatingAddress().equals("138438")){//阻止其他广播接收者收到这条广播abortBroadcast();
//              SmsManager.getDefault().sendTextMessage(sms.getOriginatingAddress(), null, "你是个好人", null, null);}
//          System.out.println(sms.getMessageBody());            }}
}

监听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 SDCardReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 区分接收到的是哪个广播String action = intent.getAction();if(action.equals("android.intent.action.MEDIA_MOUNTED")){System.out.println("sd卡就绪");}else if(action.equals("android.intent.action.MEDIA_UNMOUNTED")){System.out.println("sd卡被移除");}else if(action.equals("android.intent.action.MEDIA_REMOVED")){System.out.println("sd卡被拔出");}}
}

勒索软件

  • 接收开机广播,在广播接收者中启动勒索的Activity
  • 清单文件中配置接收开机广播
<receiver android:name="com.itheima.lesuo.BootReceiver"><intent-filter ><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter>
</receiver>
  • 权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  • 定义广播接收者
@Override
public void onReceive(Context context, Intent intent) {//开机的时候就启动勒索软件Intent it = new Intent(context, MainActivity.class);        context.startActivity(it);
}
  • 以上代码还不能启动MainActivity,因为广播接收者的启动,并不会创建任务栈,那么没有任务栈,就无法启动activity
  • 手动设置创建新任务栈的flag
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

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

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

清单文件定义广播接收者接收的类型,因为要监听应用的三个动作,所以需要接收三种广播

<receiver android:name="com.itheima.app.AppReceiver"><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 void onReceive(Context context, Intent intent) {//区分接收到的是哪种广播String action = intent.getAction();//获取广播中包含的应用包名Uri uri = intent.getData();if(action.equals("android.intent.action.PACKAGE_ADDED")){System.out.println(uri + "被安装了");}else if(action.equals("android.intent.action.PACKAGE_REPLACED")){System.out.println(uri + "被更新了");}else if(action.equals("android.intent.action.PACKAGE_REMOVED")){System.out.println(uri + "被卸载了");}
}

广播的两种类型

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

Service

  • 就是默默运行在后台的组件,可以理解为是没有前台的activity,适合用来运行不需要前台界面的代码
  • 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启
  • startService启动服务的生命周期
    • onCreate-onStartCommand-onDestroy
  • 重复的调用startService会导致onStartCommand被重复调用

进程优先级

  1. 前台进程:拥有前台activity(onResume方法被调用)
  2. 可见进程:拥有可见activity(onPause方法被调用)
  3. 服务进程:不到万不得已不会被回收,而且即便被回收,内存充足时也会被重启
  4. 后台进程:拥有后台activity(activity的onStop方法被调用了),很容易被回收
  5. 空进程:没有运行任何activity,很容易被回收

电话窃听器

  • 电话状态:空闲、响铃、接听
  • 获取电话管理器,设置侦听
 TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
tm.listen(new MyPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
  • 侦听对象的实现
 class MyPhoneStateListener extends PhoneStateListener{//当电话状态改变时,此方法调用@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// TODO Auto-generated method stubsuper.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_IDLE://空闲if(recorder != null){recorder.stop();recorder.release();}break;case TelephonyManager.CALL_STATE_OFFHOOK://摘机if(recorder != null){recorder.start();}break;case TelephonyManager.CALL_STATE_RINGING://响铃recorder = new MediaRecorder();//设置声音来源recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置音频文件格式recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setOutputFile("sdcard/haha.3gp");//设置音频文件编码recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);try {recorder.prepare();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}break;}}}

广播接收者

  • 现实中:电台要发布消息,通过广播把消息广播出去,使用收音机,就可以收听广播,得知这条消息
  • 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匹配时,系统会启动该广播接收者所在的进程,
    并把广播发给该广播接收者

短信防火墙

  • 系统发送短信广播时,是怎么把短信内容存入广播的,我们就只能怎么取出来
  • 如果短信过长,那么发送时会拆分成多条短信发送,那么短信广播中就会包含多条短信
  • 4.0之后,广播接收者所在进程如果从来没启动过,那么广播接收者不会生效
  • 4.0之后,如果系统自动关闭广播接收者所在进程,在广播中的action跟该广播接收者的action匹配时,系统会启动该广播接收者所在的进程,但是如果是用户手动关闭该进程,
    那么该进程会进入冻结状态,再也不会启动了,直到用户下一次手动启动该进程

广播的分类

无序广播

  • 所有与广播中的action匹配的广播接收者都可以收到这条广播,并且是没有先后顺序,视为同时收到

有序广播

  • 所有与广播中的action匹配的广播接收者都可以收到这条广播,但是是有先后顺序的,按照广播接收者的优先级排序

服务

  • Service
  • 运行于后台的一个组件,用来运行适合运行在后台的代码,服务是没有前台界面,可以视为没有界面的activity

进程优先级

  1. 前台进程:拥有一个正在与用户交互的Activity(onResume方法被调用)的进程
  2. 可见进程:拥有一个可见但是没有焦点的Activity(onPause方法被调用)
  3. 服务进程:拥有一个通过startService方法启动的服务
  4. 后台进程:拥有一个不可见的Activity(onStop方法被调用)的进程
  5. 空进程:没有拥有任何活动的应用组件的进程

电话录音机

电话的状态

  • 空闲状态
  • 响铃状态
  • 摘机状态

录音机

  • 音频文件的编码和格式不是一一对应的

案例3:监听SD卡状态

public class SDStatusReceiver extends BroadcastReceiver {@Overridepublic 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();}}}

案例4:手机勒索软件

public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 启动Activity,实现开机自动启动勒索软件Intent it = new Intent(context, MainActivity.class);//创建任务栈存放启动的Activityit.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(it);}}

案例5:监控应用的状态

public class APPStatusReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubString 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_REPLACED".equals(action)){Toast.makeText(context, uri.toString() + "被升级了", 0).show();}if("android.intent.action.PACKAGE_REMOVED".equals(action)){Toast.makeText(context, uri.toString() + "被卸载了", 0).show();}}}

案例6:发送自定义广播

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){//发送自定义广播Intent intent = new Intent();//广播中的action也是自定义的intent.setAction("com.itheima.zdy");sendBroadcast(intent);}}

案例7:电话录音机

public class RecorderService extends Service {private MediaRecorder recorder;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();//拿到电话管理器TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);//监听电话状态//events:决定PhoneStateListener侦听什么内容tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);}class MyListener extends PhoneStateListener{//一旦电话状态改变,此方法调用@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// TODO Auto-generated method stubsuper.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_IDLE:System.out.println("空闲");if(recorder != null){recorder.stop();recorder.release();recorder = null;}break;case TelephonyManager.CALL_STATE_RINGING:System.out.println("响铃");if(recorder == null){recorder = new MediaRecorder();recorder.setAudioSource(MediaRecorder.AudioSource.MIC);recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setOutputFile("sdcard/luyin.3gp");recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);try {recorder.prepare();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}break;case TelephonyManager.CALL_STATE_OFFHOOK:System.out.println("摘机");//开始录音if(recorder != null){recorder.start();}break;}}}}
public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//启动录音机服务Intent it = new Intent(context, RecorderService.class);context.startService(it);}}
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Intent intent = new Intent(this, RecorderService.class);startService(intent);}
}

拦截短信的广播

private class InnerSmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("InnerSmsReceiver");// 获取到短信Object[] objects = (Object[]) intent.getExtras().get("pdus");for (Object obj : objects) {SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);// 获取到短信内容String body = smsMessage.getMessageBody();// 获取到电话号码String phone = smsMessage.getDisplayOriginatingAddress();// 根据电话号码查询拦截的模式String mode = dao.findNumberMode(phone);/*** 黑名单的拦截模式1 全部拦截(电话拦截+ 短信拦截) 2 电话拦截3 短信拦截*/if ("1".equals(mode) || "3".equals(mode)) {System.out.println("被哥拦截了");//往短信拦截数据库里面添加数据abortBroadcast();}/*** 根据内容拦截(智能拦截)*/if (body.contains("xue sheng mei")) {System.out.println("学生妹被拦截了");abortBroadcast();}}}
}

注册静态广播

receiver = new InnerSmsReceiver();
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
// 设置优先级
filter.setPriority(2147483647);
// 注册一个短信监听的广播
registerReceiver(receiver, filter);

反注册广播,防止内存泄露

public void onDestroy() {super.onDestroy();// 反注册unregisterReceiver(receiver);receiver = null;// 当不用了。设置为nullmTelephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);listener = null;
}

注册广播并设置优先级

<!-- 拦截黑名单信息-->
<receiver
    android:name="com.itheima.mobilesafe_sh2.receiver.InnerSmsReceiver " ><intent-filter android:priority="1000" ><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter>
</receiver>

Android应用开发-广播和服务相关推荐

  1. SuperMap iMobile for Android 地图开发在线地图服务接入(二)

    一.对接百度地图服务 DatasourceConnectionInfo info = new DatasourceConnectionInfo(); //设置数据源别名 info.setAlias(& ...

  2. android o来电广播启动服务,Android来电监听

    本文实现来电自动接听,自动录音,自动回拨功能. public class MainActivity extends Activity { @Override protected void onCrea ...

  3. Android StudioTV开发教程(十八)建立电视频道,开发电视输入服务

    Android Studio TV开发教程 (转自Android官网https://developer.android.com/training/tv/start) 文章源自:光谷佳武 https:/ ...

  4. Android 项目开发 基于Web Service 服务的中英翻译软件(三) Web Service服务 Ksoap2 项目...

    关于Web Service Android 应用通常是运行手机平台上,手机系统的硬件资源远远比不上PC平台,不管是存储能力还是计算能力,在Android平台上运行一些小的应用时可能的,但对于需要进行大 ...

  5. Android笔记【3】---多媒体播放/广播与服务

    Android笔记[3]-多媒体播放/广播与服务 1.音乐播放 (1)创建MediaPlayer媒体播放器 存储在应用程序的res资源中的音乐文件,使用create()方法创建MediaPlayer对 ...

  6. android 启动服务同时传递数据,Android Studio开发基础之起动Service,并通过从Activity向Service传递数据...

    Android Studio开发基础之启动Service,并通过从Activity向Service传递数据 本实例演示启动Service,并通过从Activity向Service传递数据,新建一个Se ...

  7. 5G 时代的 Android App 开发入门与项目实战

    随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...

  8. 《Android/OPhone 开发完全讲义》样章和目录下载

    <Android/OPhone 开发完全讲义>一书已经出版,现提供3个样章(第1.8和14章)试读,欢迎提出宝贵意见. 购买:互动网(china-pub) 内容简介 本书近500页,共25 ...

  9. android手机上的ancs,Android BLE开发之操作IOS ANCS

    前言 之前写过两篇有关于ANCS的文章,最近一段时间老是有人问关于得到ANCS服务的问题,因为IOS ANCS不同于其他的Peripheral一样对周边所有的蓝牙设备广播自己,而是仅有连接上配对并连接 ...

最新文章

  1. Spring实现热加载MyBatis 的XML配置文件
  2. php 情书,PHP好玩的代码一(笛卡尔的情书)
  3. k8s之二进制安装etcd集群
  4. centos 修改语言、时区
  5. 【Java】求解N皇后问题
  6. 分类算法之K-近邻算法
  7. SylixOS SylixOS CAN总线驱动之三
  8. KUKA 机器人仿真软件OfficeLite
  9. 期货市场对农业的影响
  10. DISCUZ论坛管理员密码破解
  11. html设为默认打开方式,设置默认浏览器及默认打开方式设置教程
  12. 什么是世界协调时间UTC
  13. 备份恢复Lesson 11. Performing Recovery I
  14. 如何修改Win10的Windows Terminal的背景(带图文)
  15. 读取工程下的文档 统计重复的姓名 并按次数排序 java_java并打印出重复的姓名和重复的次数,并按重复次数排序...
  16. 联想微型计算机设置从u盘启动,联想笔记本设置u盘为第一启动项教程
  17. 密码学Kerberos协议理解
  18. jstree的简单使用例子
  19. 羊抗HBsAg偶联CdSe/ZnSe/ZnS量子点|抗乙肝表面抗原抗体偶联CdSe/ZnSe/ZnS量子点|羧基量子点偶联anti-HBsAg多克隆抗体
  20. 信创铺路,数据库格局颠覆的时刻到了

热门文章

  1. 虚拟机生命周期八招巧管理
  2. Silverlight的4个版本
  3. 【系统平台】模拟器-通道-模型-图形配置
  4. 简单-三层-存储过程-增删改四
  5. 动态创建DataGrid的模版列(转)
  6. 朱毅麟:为什么用户接收机定位需要接收4颗导航卫星的信号?
  7. 新的GNSS精度度量是怎样定义的?
  8. 结构体struct timeval 和 struct timespec的定义
  9. 数据科学家技能地铁图
  10. ubuntu中PyCharm的安装与卸载