服务 service
--------此笔记根据黑马程序员的授课视频所记录
Activity
网络编程1
网络编程2
广播接收者
服务
内容提供者
多媒体
1.进程概念介绍
【1】Android下四大组件都是运行在主线程中
【2】服务是在后台运行 是没有界面的activity
【3】进程的优先级
1.Foreground process 前台进程 优先级最高 相当于activity执行了onResume方法 用户正在交互
2.Visible process 可视进程 一直影响用户看得见 相当于activity执行了onPause方法
3.Service process 服务进程 通过一个startService 方法开启了一个服务
4.Background process 后台进程 相当于activity执行了onStop方法 界面不可见,但是activity并没有销毁
5.Empty process 空进程 不会维持任何组件运行
2.start方式开启服务的特点
【1】定义四大组件的方式是一样的
【2】定义一个类继承Service
【3】第一次开启点击按钮开启服务 服务执行onCreate方法和onStartCommand方法
【4】第二次点击开始按钮 再次开启服务 服务执行onStartCommand方法
【5】服务一旦被开启 服务就会后台长期运行 直到用户手工停止
3.电话窃听器案例
TelephoneManager 提供关于设备的一些信息
实现步骤
[1]定义一个服务 开启服务 记得在清单文件配置服务(AS直接创建一个服务)
[2]在服务的onCreate方法里获取TelephoneManager
TelephonyManager tm = (TelephonyManager) getSystemService(TELECOM_SERVICE);
[3]注册电话的监听
tm.listen(new MyPhoneListener(), PhoneStateListener.LISTEN_CALL_STATE);
[4]定义一个类来监听电话的状态
public class MyPhoneListener extends PhoneStateListener {
//当电话设备状态发生改变时调用
@Override
public void onCallStateChanged(int state, String incomingNumber) {
//具体判断电话的状态
switch (state) {
//空闲状态
case TelephonyManager.CALL_STATE_IDLE:
break;
//电话接听状态
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
//电话响铃状态
case TelephonyManager.CALL_STATE_RINGING:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
下面代码是加入了真正的录音逻辑
//定义一个类用来监听电话的状态
public class MyPhoneListener extends PhoneStateListener {
private MediaRecorder recorder; //创建一个录音机的实例
//当电话设备状态发生改变时调用
@Override
public void onCallStateChanged(int state, String incomingNumber) {
//具体判断电话的状态
switch (state) {
//空闲状态
case TelephonyManager.CALL_STATE_IDLE:
if (recorder!=null){
recorder.stop();//停止录音
recorder.reset();//重置
recorder.release();//释放资源
}
break;
//电话接听状态
case TelephonyManager.CALL_STATE_OFFHOOK:
recorder.start();
break;
//电话响铃状态
case TelephonyManager.CALL_STATE_RINGING:
Log.d("******", "onCallStateChanged: 准备一个录音机");
//创建实例
recorder = new MediaRecorder();
//设置音频来源
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);//录制双方通话
//设置输出的格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//3gp格式
//设置音频的编码方式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置存放的文件路径
recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
try {
//准备录
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
4.使用服务注册特殊的广播接收者
和在activity中注册特殊的广播接收者一样只是放在了Service的生命周期方法里
public void onCreate(){
//创建Receiver对象
MyReceiver myReceiver = new MyReceiver();
//创建IntentFliter对象
IntentFilter intentFilter = new IntentFilter();
//添加要注册的action
intentFilter.addAction("android.intent.action.SCREEN_OFF");//锁屏
intentFilter.addAction("android.intent.action.SCREEN_ON");//解屏
//动态注册广播接收者
registerReceiver(myReceiver,intentFilter);
}
//当Service销毁的时候要取消广播接收者
@Override
protected void onDestroy() {
unregisterReceiver(myReceiver);
super.onDestroy();
}
5.bindService开启服务的特点
【1】第一次点击按钮会执行服务的onCreate方法和onBind方法
【2】当onBind方法返回值为null时 onserviceConnected方法时不执行的
【3】第二次点击按钮 服务没有响应
【4】不求同生,但求同死 指的是调用者(activity)和服务之间
【5】服务不可以多次解绑,多次解绑会报异常
【6】通过bind方式开启的服务 服务不能再设置页面找到 相当于是一个隐形的服务
具体的代码开启实现方式
6.为什么要引入bindService
为了调用服务里的方法
7.通过biandService方式调用服务方法里面的过程
【1】在服务的内部定义一个方法,让activity去调用
【2】在服务的内部定义一个中间人对象(IBinder)
public class MyBinder extends Binder{
public void Test(){
//此方法里可以调用需要调用服务的方法
}
}
【3】把定义的中间人对象在onBind方法里返回
public IBinder onBind(Intent intent) {
return new MyBinder();
}
【4】在mainActivity的onCreate方法里面调用bindService方法 目的是为了获取我们定义的中间人对象
Intent intent = new Intent(this,DemoService.class);
//连接到DemoService这个服务
conn = new MyConn();
bindService(intent,conn,BIND_AUTO_CREATE);
【5】获取中间人对象
private class MyConn implements ServiceConnection{
//当服务连接成功时调用此方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取中间人对象
myBinder = (DemoService.MyBinder) service;
}
//当服务失去来连接时调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
【6】拿到了中间人对象就可以间接调用服务里面的方法
public void click7(View view) {
myBinder.Test();
}
【7】当Activity销毁的时候解绑服务
protected void onDestroy() {
//当activity销毁的时候解绑服务
unbindService(conn);
super.onDestroy();
}
8.通过接口方式调用服务里面的方法
接口可以隐藏代码内部的细节 让程序员暴露自己只想暴露的方法
定义一个接口,把想暴露出去的方法放到接口中去,将原来的MyBinder类变成private私有的。
让MyBinder实现这个接口
注意,此时定义的中间人对象的类型发生了改变,变成了接口的类型,因为Java的多态
9.百度音乐盒框架
补充:混合方式开启服务
需求:我既想让服务在后台长期运行 又想调用服务里的方法
[1]先调用startService 方法开启服务 能够保证服务在后台长期运行
[2]调用bindService方法获取中间人对象
[3]调用unbindService解绑服务
[4]调用stopService
public class MusicActivity extends AppCompatActivity {
Iservice iservice;//定义的中间人对象
MyConn myConn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
//开始混合开启服务
//1.先调用startService 目的是保证服务能在后台长期运行
Intent intent = new Intent(this,MusicService.class);
startService(intent);
myConn = new MyConn();
bindService(intent,myConn,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
//销毁时解绑
unbindService(myConn);
super.onDestroy();
}
//播放音乐
public void click1(View v){
iservice.callplayMusic();
}
//暂停音乐
public void click2(View v){
iservice.callpauseMusic();
}
//继续播放音乐
public void click3(View v){
iservice.callrePalyMusic();
}
//上一首
public void click4(View v){
}
//下一首
public void click5(View v){
}
//用来监听服务的状态
private class MyConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iservice = (Iservice) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
public interface Iservice {
//把想暴露的方法都放到接口中去
public void callplayMusic();
public void callpauseMusic();
public void callrePalyMusic();
}
public class MusicService extends Service {
MediaPlayer mediaPlayer;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
//播放音乐逻辑
public void playMusic(){
Log.d("音乐", "playMusic:播放了");
}
//暂停音乐逻辑
public void pauseMusic(){
Log.d("音乐", "playMusic:暂停了");
}
//继续播放音乐逻辑
public void rePalyMusic(){
Log.d("音乐", "playMusic:重新播放了");
}
//在服务的内部定义一个中间人对象
private class MyBinder extends Binder implements Iservice{
@Override
public void callplayMusic() {
playMusic();
}
@Override
public void callpauseMusic() {
pauseMusic();
}
@Override
public void callrePalyMusic() {
rePalyMusic();
}
}
}
10.aidl介绍
本地服务:运行在自己应用里面的服务
远程服务:运行在其他应用里面 的服务
实现进程间通信(IPC)
AIDL(Android Interface Definition Language)是Android系统自定义的接口描述语言,是Android平台中实现进程间通讯方式一种,属轻量级通讯机制,有着实现简单、效率较高等优点…
总结:使用步骤
[1]把Iservice.java文件变成一个aidl文件
[2]aidl这个语言不认识public 所以把public去掉即可
[3]系统会自动生成一个Iservice.java文件 系统 自动帮助我们生成了一个Stub类
[4]我们自己定义的中间人MyBinder类对象直接继承Stub类就好了,不用再继承Binder然后再实现IService接口
[5]保证两个应用的aidl文件是同一个 保证aidl文件所在的包名相同
[6]获取中间人对象的方式不一样了
PS:注意!此时在activity里的onCreate方法里new Intent时不能直接传入参数时用.class的方法了,需要用意图过滤器实现
11.aidl的应用场景
比如 支付宝应用 调用支付功能
12.今日总结
【1】进程的概念 优先级:前台 可视 服务 后台 空进程(了解)
【2】如何定义服务 定义一个类继承Service
【3】startService开启服务的特点 服务长期在后台运行 直到用户手动停止(必须掌握)
【4】bindService 服务开启的特点 不求同时开始,但求同时结束 Activity销毁了 服务也跟着销毁了(掌握)
【5】电话窃听器实例(掌握)
telephoneManager:getSystemService();
tm.listen
电话的三种状态 空闲 响铃 接听
录音机:MeidiaRecoder 涉及权限较多
【6】使用服务注册特殊广播接收者:把注册的逻辑放到服务当中(掌握)
【7】使用bindService调用服务方法的流程(掌握)
(1)在服务内部定义一个方法
(2)定义一个中间人对象(IBinder)
(3)在onBind方法返回
(4)通过bindService去获取中间人对象
(5)通过中间人对象去间接的调用服务里的方法
【8】通过抽取接口的方式调用服务里的方法
【9】混合方式开启服务
startService()保证服务在后台长期运行
bindService()获取中间人对象 可以调用服务里的方法
unbindService()解绑服务
stopservice方法关不关闭看情况
【10】aidl 是解决进程间通信的 IPC