广播接收者
- BroadcastReceiver
- 接收系统发出的广播
- 现实中的广播:电台为了传达一些消息,而发送的广播,通过广播携带要传递的消息,群众只要买了收音机,就可以收到广播了
- Android中的广播:系统在运行过程中,会发生很多事件,系统为了让其他应用知道系统发生了这个事件,会发送一个对应事件的广播,比如:电量改变,收到短信,拨打电话,屏幕解锁,系统开机,只有注册一个广播接收者,就可以接收到系统发送的广播。
IP拨号器
系统拨打号码时,会发出一个广播,广播中会携带拨打的号码,注册广播接收者接收这个广播,取出这个号码,修改号码,然后把修改的号码重新放入广播。
-
原理
定义方式
- 定义一个类继承BroadCastReceiver
-
在清单文件中配置该类,并指定接收的广播种类必须配置intent-filter。
需要加入权限:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
- 广播是通过Intent发送的,Intent中会携带一个action,系统会在所有的清单文件中寻找,看哪个一个广播接收器的intent-filter 和广播中的intent是匹配的,那么这个广播接收器就会收到这条广播。
- 广播运行在哪个进程里面就看她运行在哪个项目里面。
如果关掉应用进程之后,广播接收者还是会接收,即便没有启动应用进程,广播发出来时,系统也会启动这个进程,然后把广播交给广播接受者。
广播接受者所在进程是不怕被杀掉的。
短信防火墙原理
需要的权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
可以取大于1000的数,取整数的最大值
- 一条短信是由很多 条短信拼接起来的,所以是数组形式
-
短信拦截必须在有短信时就拦截就必须优先级要高,系统短信优先级不高于1000,先一步收到短信广播,然后拦截广播,短信应用就收不到短信的。
- 4.0之后,用户手动开启进程,那么广播接收者才能生效
- 4.0之后,用户手动停止进程,那么广播接受者再也不会启动了,直到用户下一次手动启动进程。
监听SD卡状态
监听SD卡不需要权限
开机勒索软件
-
在广播接收器中启动Activity 出现错误
- 启动一个新的任务栈来保存Activity,之前我们启动Activity是直接点击图标启动的,启动Activity本身是有任务栈的,我们现在在一个Activity任务栈之外启动Activity就会出现问题。因为当前没有任务栈。需要直接创建一个任务栈。
应用的安装卸载和更新
-
注册广播
-
广播接收处理
发送自定义广播
-
发送广播
*接收广播
有序和无序广播
无序广播
所有与广播中的Intent匹配的广播接收者,都可以收到这条广播,并且不分先后顺序,视为同时收到。有序广播
所有与广播中的intent匹配的广播接收者,都可以收到这条广播,但是分先后顺序,优先级高的先收到,优先级低的后收到。
服务
Service
四大组件之一
运行于后台,没有前台界面,用于运行需要在后台运行的代码
如:下载任务,音乐播放。
如果下载线程放在Activity中时,
按home和返回键 销毁Activity之后 下载还可以运行,这是因为线程还在进程运行,但是进程被杀掉之后,线程就会被销毁。当内存不足时就会杀掉进程,因此不要把下载放在Activity中。Empty 进程(没有任何活动的应用组件(Activity和Service))
一个进程不包含任何活跃的应用组件(指的是服务和Activity),保持该类型进程活跃的原因只是是缓存,提高下次组件在该进程中的开启速度。
该进程很容易被杀掉后台进程(如按home键)
如果一个进程持有一个对用户不可见的Activity时(该activity的onStop()方法已经被调用),这些进程对用户的体验没有直接的影响。
很容易被杀死服务进程(相比bindService而言,这个才是真正用来下载,不到万不得已不会被杀死)
拥有一个服务的进程。
该进程中正在运行的是以startService()方法开启的服务。可见进程
拥有一个不在前台但对用户依然可见的Activity(onPause()方法被调用)的进程
拥有一个与可见Activity(onPause()方法被调用)绑定的服务(特指远程服务)
-
前台进程
- 拥有一个正在与用户交互的Activity(onResume()方法调用)
- 拥有一个与正在与用户交互的Activity绑定的服务(特指远程服务)
- 拥有一个运行在前台的服务(服务调用了startForeground())
- 拥有一个正在执行其中一个生命周期方法( onCreate(),onStartCommand(),or onDestory())的服务。
保证生命周期执行完毕,短暂提高优先级,保证代码执行完毕,完成后就自动降为服务进程。在内存不足不被杀掉。 - 拥有一个正在执行onReceive的方法的广播接受者。执行完毕该杀就被杀。
服务的启动和停止
-
定义方式:创建java类再继承Service类,清单文件做配置。
可以理解为:没有界面的Activity。
- 服务单位生命周期
startService的生命周期:
onStartCommand:可以多次被调用
onCreate:只会被调用一次
onDestory:值会被调用 - onCreate->onStartCommand->onDestory
重复的startService不会调用onCreate只会重复调用onStartCommand
通话录音机
- 空闲
- 响铃
- 摘机
先监听电话状态
MediaRecorder使用方法
服务的两种启动方式及生命周期
startService
- 通过startService启动的服务,该服务所在的进程会变成服务进程。
- Service 与启动它的Activity没有关系。
bindService
- 通过bindService启动的服务,进程优先级不变。
- 绑定出来的Service不是服务进程,它的优先级跟他本身绑定的Activit有关,Activity 是后台的,那就是后台进程,Activity没有了,那就是空进程。
绑定出来的Service是不能作为后台操作的。很容易死掉进程。
不能再次解绑的,重复解绑会报错。
绑定服务后,直接按返回键会报错。说明绑定服务不能作为后台操作
- 绑定的服务于启动它的Activity是同生共死的,Activity销毁了,服务也要销毁。服务销毁了,activity不销毁。
调用服务中的方法
回调类ServiceConnection
把中间人的方法抽取到接口中
为什么要这么做,不私有化方法呢?
模拟音乐播放器
混合启动Service(startService和bindService)
start->bind->unbind->stop
因为要保证音乐播放器退出后音乐还在播放,就必须启动服务进程
- 一定要先启动后绑定
先启动startService
onCreate->onStartCommand
再绑定
->onBind
再解绑 服务还在
->onUnbind ( 不会被摧毁)
再摧毁
->onDetory - 如果先bindService(逻辑会出问题)
onCreate->onbind
再startService
->onStartCommand
再stopService
->服务什么也不干
最后解绑
->onUnbind(会销毁)
使用代码注册和反注册广播接受者
清单文件注册
- 广播接收者永远生效,除非卸载应用,或者手动停止进程(如防火墙)
代码注册
通常和service联系在一起,一般启动服务来注册。
需要广播接收者生效时,注册它,不需要时,反注册它,反注册之后,广播接收者就失效了。(只在需要时注册)
-
特殊广播接收者,必须代码注册。
这种需求没有必要一直生效。因为这些广播变化得很快,次数很频繁。
(清单文件注册了而没有代码注册也接收不到)- 屏幕开关
- 电量改变
第一步定义服务并在清单文件中注册服务
- 第二步定义广播接收器
启动和绑定远程服务
服务的分类
都是在手机上与web不一样
本地服务
- 与启动者都在同一应用的服务
远程服务
- 与启动者不在同一应用的服务
本地服务使用显示启动
远程服务使用隐式启动
注意:
Android 5.0 之后 Service必须显示启动,不然会报错
解决方案:
远程服务中使用aidl
进程间通信
- AIDL
android interface definition language
在Android中进行进程间通讯
步骤:
远程Service
1.把接口文件的后后缀名.aidl;(在gen中自动生成.java文件)
2.aidl文件中的所有东西都是public ,不需要访问修饰符;
3.中间人对象继承Stub,这个抽象类Stub已经继承了Binder并实现了aidl里面的方法。
访问远程服务
1.把上述的aidl文件复制到访问远程服务的工程中,然后aidl所在的包名必须和远程Service中的aidl一致。
2.把获取的中间人对象使用Stub.asInterface强转。
支付宝远程服务
进程优先级的补充
确定取消对话框
单选对话框
setMessage 是绝对不能设置的,会将单选内容盖掉。
设置多选对话框
设置进度条对话框
样式和主题
- 样式和主题定义的方式是一模一样的
- 布局文件中使用样式
-
清单文件中使用主题
国际化
图片也能国际化: