第八天 服务

##01_服务和进程优先级


* 什么是服务?


windows下的服务:没有界面、长期运行在后台的应用程序;
  android下的服务:应用程序的一个组件,没有界面activity,长期运行在后台;

  进程:是应用程序运行的载体。
  进程与应用程序之间的关系: linux操作系统创建一个进程,这个进程负责运行dalvik虚拟机,Android的应用程序都是运行在dalvik虚拟机上的。

 




* 进程的生命周期:


   1、应用程序一启动的时候就创建了进程;
   2、当应用程序退出的时候进程并没有退出;
   3、只有手工停止这个进程,进程才会结束;




操作系统尽量长时间的运行应用程序的进程,为了保证内从空间不被大量占用,它会按照进程的优先级,从低到高一级一级的杀死进程,直到内存空间被清理的差不多。




进程的等级:


1. Foreground process(前台进程)


应用程序,用户正在操作,activity的onresume方法被执行了,可以相应点击事件。


2. Visible process   (可视进程)


应用程序的ui界面,用户还可以看到,但是不能操作了。


3. Service process   (服务进程)


应用程序没有界面,但是有一个后台的服务还处于运行状态


4. Background process(后台进程)


应用程序没有服务处于运行状态,应用程序被最小化了,activity执行了onstop方法


5. Empty process      (空进程)


没有任何组件运行,所有的activity都关闭了,任务栈清空了




##2_服务的特点


* 服务的特点:
 
服务被创建时调用onCreate、onStartCommand;
  服务只能被创建一次,可以开启多次onStartCommand;
  服务只能被停止一次; 
没有onPause、onStop、onResume、onRestart方法,因为service没有界面,长期运行在后台。


* 生命周期的方法:
 
   onCreate:服务被创建的时候调用这个方法;
onStartCommand :开启服务
   onDestroy:销毁服务




##3_电话窃听器的模板代码(重点)


* 步骤:


1、在工程中添加一个服务Service,重写onCreate方法;
2、在清单文件中配置服务;
   3、在activity中开启服务;
4、在onCreate方法中使用TelephonyManager监听电话的状态;
5、在清单配置文件中添加权限


* 示例代码:


1、在工程中添加一个服务Service,重新onCreate方法:
 public class DHQTService extends Service {
/**
* 当服务被创建的时候调用这个方法
*/
@Override
public void onCreate() {
System.out.println("=========onCreate=========");
super.onCreate();

TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);

}
}

   2、在清单文件中配置服务:

<service android:name="com.itheima.dhqtq.DHQTService"></service>

3、在activity中开启服务:

service = new Intent(this,DHQTService.class);
//开启服务
startService(service);

   4、在onCreate方法中使用TelephonyManager监听电话的状态:

/**
* 当服务被创建的时候调用这个方法
*/
@Override
public void onCreate() {
System.out.println("=========onCreate=========");
super.onCreate();

TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);

}




/**
*自定义一个电话状态监听器,监听电话
*/
private class mylistener extends phonestatelistener {

private MediaRecorder r;

@Override
public void onCallStateChanged(int state, String incomingNumber) {

try {
// super.onCallStateChanged(state, incomingNumber);
System.out.println("====state===============" + state);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 闲置状态
System.out.println("关闭录音机,上传音频文件..................");
if(r != null){
r.stop();
r.release();
r = null;
//上传文件
}
break;

case TelephonyManager.CALL_STATE_RINGING:// 闲置状态
System.out.println("准备好录音机,准备录音..................");

r = new MediaRecorder();

r.setAudioSource(MediaRecorder.AudioSource.MIC);
r.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

//r.setOutputFile("/mnt/sdcard/info.3gp");
r.setOutputFile(Environment.getExternalStorageDirectory()+"/info.3gp");
r.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
r.prepare(); 

break;

case TelephonyManager.CALL_STATE_OFFHOOK:// 闲置状态
System.out.println("开始录音..................");
r.start();
break;

}
} catch (Exception e) {
e.printStackTrace();
}
}

}


5、在清单配置文件中添加权限:


<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>






##01_start开启服务的生命周期(重点)


   * 服务的特点:
 
服务被创建时调用onCreate、onStartCommand;
  服务只能被创建一次,可以开启多次onStartCommand;
  服务只能被停止一次; 
没有onPause、onStop、onResume、onRestart方法,因为service没有界面,长期运行在后台。


* 生命周期的方法:
 
   onCreate:服务被创建的时候调用这个方法;
onStartCommand :开启服务
   onDestroy:销毁服务


##02_bind方式开启服务的生命周期(重点)


    bindService绑定服务、unBindService解除绑定的服务;
服务是在被绑定的时候被创建,调用oncreate、onbind方法;
    服务只能被绑定一次;
服务只能被解除一次,接触绑定的时候调用onUnbind、onDestrory方法,如果多次解除绑定会抛出异常;
    


    推荐的方式:


    startService:开启并创建一个服务,服务长期运行在后台;
    bindService:绑定服务,可以调用服务里面的方法;
    unBindService:解除服务,停止服务里面的方法;
    stopService:停止服务,销毁服务对象;
    


##03_为什么要引入bindservice的API

为了调用服务中的业务逻辑方法。







##04_绑定服务调用服务方法的过程


    通过bindservice方式实现调用服务里面业务逻辑方法:
    步骤:


1、在服务类中创建一个中间人MyBinder,继承了Binder,Binder实现了IBinder接口:


    public class MyBinder extends Binder{
}


2、在服务类里面创建了一个MyBinder的成员变量:
private MyBinder myBinder;


    3、在MyBinder类中写一个方法用于调用服务的业务逻辑方法:
public class MyBinder extends Binder{

//使用中间人对象调用服务里的方法
public void callMethodInService(){
methodInService();
}

}


    4、在activity中bindService时,定义了ServiceConnection,在这个连接中实现了两个:


private class MyConn implements ServiceConnection {
/**
* 服务连接成功时调用这个方法
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//得到服务绑定成功后返回的中间人MyBinder对象
myBinder = (MyBinder) service;

}

/**
* 服务断开成功时调用这个方法
*/
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("-------onServiceDisconnected-------");

}

}


     5、通过在activity中通过中间人条用服务的业务逻辑方法:
myBinder.callMethodInService();






##05_绑定服务抽取接口(重点)


    接口(interface): 对外开放暴露的功能,但是不会暴露功能实现的细节;
    让中间人实现服务接口的目的:只对外暴露接口里面业务逻辑方法,隐藏中间人里面的其他方法;


  步骤:


    1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法:
public interface IService {
public void callMethodInService();
}
    
    2、让服务中的中间人实现了服务的接口类:
private class MyBinder extends Binder implements IService{

//(实现服务接口中的方法)使用中间 人调用服务里的方法
public void callMethodInService(){
methodInService();
  }
}


3、在activity中声明接口的成员变量:
private IService myBinder;


    4、强制转换成服务的接口类型
private class MyConn implements ServiceConnection {


/**
* 服务连接成功时调用这个方法
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//强制转换成服务的接口类型
myBinder = (IService) service;
}


     5、在activity中通过接口的成员变量调用服务的业务逻辑方法:
public void call(View view){
myBinder.callMethodInService();


}


##06_绑定服务的应用场景

     应用场景:


     1、需要在后台运行一定的业务逻辑,而且需要与服务器端交互数据,都是写在服务里面的。
     2、天气预报、股票行情软件;


##07_利用服务注册广播接收者


      操作频繁的广播事件,如果只是在清单配置文件配置,是不生效的。需要使用代码注册才能生效;


     步骤:


     // 注册广播接收者
// 1、得到广播接收者的对象


ScreenBroadCastReceiver screenReceiver = new ScreenBroadCastReceiver();


// 2、创建一个intentFilter对象
IntentFilter filter = new IntentFilter();


// 3、注册接收的事件类型
filter.addAction("android.intent.action.SCREEN_ON");
filter.addAction("android.intent.action.SCREEN_OFF");


// 4、注册广播接收者
this.registerReceiver(screenReceiver, filter);














##08_远程服务aidl的写法(重点)


  本地服务:写在自己的应用程序的工程里的服务 ,使用自己应用程序的进程运行这个服务;


    远程服务:写在别的应用程序的工程里的服务,使用别的应用程序的进程运行这个服务(安装在同一个手机上的应用程序);


IPC: Inter Process Communication(进程间的通讯);


    aidl: Android Interface definition language 安卓接口定义语言;
    aidl的接口类里面不需要public 、protected、private 等修饰符,默认是公开共享;




步骤:


    1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法:

    2、让服务中的中间人实现了服务的接口类:



3、修改并拷贝接口文件:




4、在本地服务的工程中的activity里,绑定服务:



5、通过接口调用远程服务的方法:












1 进程概念介绍
  四大组件都是运行在主线程 
  Android中的服务 也是在后台运行  可以理解成是在后台运行并且是没有界面的Activity




  (1)Foreground process 前台进程  用户正在交互  可以理解成相 当于 Activity执行onResume方法
  (2)Visible process 可视进程 用户没有在交互 但用户还一直能看得见页面 相当于Activity执行了onPause方法 
  (3)Service Process  服务进程  通过startService()开启了一个服务
  (4)Background process  后台进程  当前用户看不见页面 相当于Activity执行了onStop方法
  (5)Empty process 空进程








2 start方式开启服务的特点
  服务是在后台运行 可以理解成是没有界面的activity
  定义四大组件的方式都是一样的  
  定义一个类继承Service
  
  特点:
  (1)服务通过startservice方式开启 第一次点击按钮开启服务 会执行服务的onCreate 和 onStart方法
  (2)如果第二次开始在点击按钮开启服务 服务之后执行onStrat方法
  (3)服务被开启后 会在设置页面里面的 running里面找得到这个服务 
  ***(4)startservice 方式开启服务 服务就会在后台长期运行 直到用户手工停止 或者调用StopService方法 服务才会被销毁
 








#bindService 方式开启服务的特点 
 09-10 03:15:00.603: E/ActivityThread(11793): Activity com.itheima.service.MainActivity has leaked ServiceConnection com.itheima.service.MainActivity$MyConn@b6445bf8 that was originally bound here
09-10 03:15:00.603: E/ActivityThread(11793): android.app.ServiceConnectionLeaked: Activity com.itheima.service.MainActivity has leaked ServiceConnection com.itheima.service.MainActivity$MyConn@b6445bf8 that was originally bound here
  
  (1)当点击按钮第一次开启服务 会执行服务的onCreate方法 和 onBind()方法
   (2) 当我第二次点击按钮在调用bindservice  服务没有响应 
   **(3) 当activity销毁的时候服务也销毁  不求同时生但求同时死 
  (4)通过bind方式开启服务  服务不能再设置页面里面找到  相当于是一个隐形的服务
  (5)bindservice不能多次解绑 多次解绑会报错




3 电话窃听器案例
  new Thread(){}.start();  服务有啥区别 股票应用
  实现步骤 
  (1)先定义一个服务 服务用来监听电话状态 开启服务
  (2)在服务的oncreate方法里面实例化TelephoneManager类的实例  
  
  (3)注册一个电话监听 
   
    (4)定义一个电话监听的类 代码如下 
1.//监听电话的状态2. private class MyPhoneStateListenrer extends PhoneStateListener{3. //当设备的状态发生改变的时候调用4. @Override5. public void onCallStateChanged(int state, String incomingNumber) {6. 7. //[3]具体判断一下  电话是处于什么状态8. switch (state) {9. case TelephonyManager.CALL_STATE_IDLE:  //空闲状态10. 11. break;12. 13. case TelephonyManager.CALL_STATE_OFFHOOK://接听状态 14. 15. System.out.println("开始录");16. break;17. 18. case TelephonyManager.CALL_STATE_RINGING:  //响铃状态19. System.out.println("我准备一个录音机出来 ");20.21. break;22. }23. 24. 25. 26. super.onCallStateChanged(state, incomingNumber);27. }28. 29. }(5) 实现录音的功能 
1.//[1]获取MediaRecorder类的实例2. recorder = new MediaRecorder();3. //[2]设置音频的来源4. recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //zet 5. //[3]设置音频的输出格式 6. recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);7. //[4]设置音频的编码方式 8. recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);9. //[5]保存的文件路径10. recorder.setOutputFile("/mnt/sdcard/luyin.3gp");11. //[5]准备录音12. try {13. recorder.prepare();14. } catch (IllegalStateException e) {15. e.printStackTrace();16. } catch (IOException e) {17. e.printStackTrace();18. } (6)记得加上相应的权限 
1.  <uses-permission android:name="android.permission.READ_PHONE_STATE"/>2.  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />3.  <uses-permission android:name="android.permission.RECORD_AUDIO" />4.  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>










   
4 使用服务注册特殊的广播接收者
   (1)创建我们要注册的广播接收者 
1.public class ScreenReceiver extends BroadcastReceiver {2.3. @Override4. public void onReceive(Context context, Intent intent) {5.6. //获取广播事件的类型7. String action = intent.getAction();8. 9. if ("android.intent.action.SCREEN_OFF".equals(action)) {10. 11. System.out.println("说明屏幕锁屏了");12. }else if("android.intent.action.SCREEN_ON".equals(action)){13. 14. System.out.println("说明屏幕解锁了");15. }16. 17. 18. 19. }20.21.}(2)创建一个服务 用来注册广播接收者  代码如下
1.package com.itheima.registerbroadcast;2.3.import android.app.Service;4.import android.content.Intent;5.import android.content.IntentFilter;6.import android.os.IBinder;7.8.public class ScreenService extends Service {9. 10. private ScreenReceiver receiver;11.12. @Override13. public IBinder onBind(Intent intent) {14. return null;15. }16. 17. //当服务第一次启动的时候调用18. @Override19. public void onCreate() {20. 21. //在这个方法里面注册广播接收者22. //[1]获取ScreenReceiver实例23.        receiver = new ScreenReceiver();24. 25.        //[2]创建IntentFilter对象26. IntentFilter filter = new IntentFilter();27. //[3]添加注册的事件28. filter.addAction("android.intent.action.SCREEN_OFF");29. filter.addAction("android.intent.action.SCREEN_ON");30. //[4]通过代码的方式注册31. registerReceiver(receiver, filter);32. 33. super.onCreate();34. }35. 36. //当服务销毁的时候调用37. @Override38. public void onDestroy() {39. 40. //当actvivity销毁的时候  取消注册广播接收者 41. unregisterReceiver(receiver);42. 43. 44. super.onDestroy();45. }46.47.}(3)一定要记得配置service
  
 




 
6 为什么要引入bindService
  目的为了调用服务里面的方法




7 通过bindservice方式调用服务方法里面的过程
  (1)定义一个服务 服务里面有一个方法需要Activity调用
      
  (2)定义一个中间人对象(IBinder) 继承Binder; 
     




  (3)在onbind方法里面把我们定义的中间人对象返回  
     
  (4)在Activity的oncreate 方法里面调用bindservice 目的是为来获取我们定义的中间人对象
    




  (4.1)获取中间人对象
   




  (5)拿到中间人对象后就可以间接的调用到服务里面的方法 
      




8 通过接口方式调用服务里面的方法
  接口可以隐藏代码内部的细节 让程序员暴露自己只想暴露的方法
  (6)定义一个接口 把想暴露的方法都定义在接口里面 
  (7)我们定义的中间人对象 实现我们定义的接口
  (8)在获取我们定义的中间人对象方式变了
      
    
9 百度音乐盒框架


  需求:我既想让服务在后台长期运行  又想调用服务里面的方法  
  混合方式开启服务 
  (1)先调用startService()方法 保证服务在后台长期运行
  (2)调用bindservice()目的获取我们定义的中间人对象 调用服务里面的方法
  (3)unbindservice() 看这时候服务会不会销毁
  (4)最后调用stopservice() 停止服务 
    




10 aidl介绍
  (1)远程服务 运行在其他应用里面的服务  
  (2)本地服务 运行在自己应用里面的服务 
  (3)进行进程间通信(IPC)
  (4)aidl Android interface Defination Language Android接口定义语言 专门是用来解决进程间通信的 
  
 aidl 实现步骤和之前调用服务里面的方法的区别 
 (1)先把Iservice.java文件变成aidl文件 
 (2)adil 不认识public 把public 给我去掉
 (3)会自动生成一个Stub类 实现ipc 
 (4)我们定义的中间人对象 直接继承stub
 (5)想要保证2个应用程序的aidl文件是同一个 要求aidl文件所在包名相同
 (6)获取中间人对象Stub.asinterface(Ibinder obj) 




11 aidl的应用场景 
 支付宝  非常有名 支付的方法  

  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值