Service
什么是服务?
windows下的服务:没有界面、长期运行在后台的应用程序;
android下的服务:应用程序的一个组件,没有界面activity,长期运行在后台;
进程:是应用程序运行的载体。
进程与应用程序之间的关系: linux操作系统创建一个进程,这个进程负责运行dalvik虚拟机,Android的应用程序都是运行在dalvik虚拟机上的。
进程的生命周期:
1、应用程序一启动的时候就创建了进程;
2、当应用程序退出的时候进程并没有退出;
3、只有手工停止这个进程,进程才会结束;如果是自动关闭,内存充足就会重启。
操作系统尽量长时间的运行应用程序的进程,为了保证内从空间不被大量占用,它会按照进程的优先级,从低到高一级一级的杀死进程,直到内存空间被清理的差不多。
进程的等级:
1. Foreground process(前台进程)
应用程序,用户正在操作,activity的onResume方法被执行了,可以相应点击事件。(onResume)
2. Visible process (可视进程)
应用程序的ui界面,用户还可以看到,但是不能操作了。(onPause)
3. Service process (服务进程)
应用程序没有界面,但是有一个后台的服务还处于运行状态.
4. Background process(后台进程)
应用程序没有服务处于运行状态,应用程序被最小化了,activity执行了onstop方法.(onStop)
5. Empty process (空进程)
没有任何组件运行,所有的activity都关闭了,任务栈清空了
服务的特点
服务被创建时调用onCreate、onStartCommand;
服务只能被创建一次,可以开启多次onStartCommand;
服务只能被停止一次 onDestroy;
没有onPause、onStop、onResume、onRestart方法,因为service没有界面,长期运行在后台。
生命周期的方法:
onCreate()--->onStartCommand()--->onDestroy()(stopService())
onCreate:服务被创建的时候调用这个方法;
onStartCommand :开启服务
onDestroy:销毁服务
电话qietingqi的模板代码(重点)
步骤:
1、在工程中添加一个服务Service,重写onCreate方法;
2、在清单文件中配置服务;
3、在activity中开启服务,在onCreate方法中使用TelephonyManager监听电话的状态;
4、创建一个广播接收者,开机即开启录音服务;
5、在清单文件中配置广播接收者
6、在清单配置文件中添加权限
代码:
1 package com.ahu.lichang.recorderservice; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.media.MediaRecorder; 6 import android.os.IBinder; 7 import android.support.annotation.Nullable; 8 import android.telephony.PhoneStateListener; 9 import android.telephony.TelephonyManager; 10 11 /** 12 * Created by ahu_lichang on 2017/3/24. 13 */ 14 public class RecorderService extends Service{ 15 private MediaRecorder recorder; 16 /** 17 * 绑定服务时,要调用此方法 18 * @param intent 19 * @return 20 */ 21 @Nullable 22 @Override 23 public IBinder onBind(Intent intent) { 24 return null; 25 } 26 27 /** 28 * 创建服务时,调用此方法 29 */ 30 @Override 31 public void onCreate() { 32 super.onCreate(); 33 //拿到系统服务电话管理器 34 TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); 35 //监听电话状态 36 tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE); 37 } 38 class MyPhoneStateListener extends PhoneStateListener { 39 @Override 40 public void onCallStateChanged(int state, String incomingNumber) { 41 super.onCallStateChanged(state, incomingNumber); 42 switch (state){ 43 case TelephonyManager.CALL_STATE_IDLE://空闲状态 44 if(recorder != null){ 45 recorder.stop(); 46 recorder.release(); 47 recorder = null; 48 } 49 break; 50 case TelephonyManager.CALL_STATE_RINGING://响铃状态 51 if(recorder == null){ 52 //创建录音机 53 recorder = new MediaRecorder(); 54 //设置声音来源 55 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//MIC:只能录自己的声音 56 //设置音频文件格式 57 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 58 recorder.setOutputFile("storage/sdcard/luyin.3gp"); 59 //设置音频文件编码 60 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 61 try { 62 recorder.prepare(); 63 } catch (Exception e) { 64 e.printStackTrace(); 65 } 66 } 67 break; 68 case TelephonyManager.CALL_STATE_OFFHOOK://摘机状态 69 if(recorder != null){ 70 recorder.start(); 71 } 72 break; 73 } 74 } 75 } 76 77 /** 78 * 开启服务时,调用此方法 79 * @param intent 80 * @param flags 81 * @param startId 82 * @return 83 */ 84 @Override 85 public int onStartCommand(Intent intent, int flags, int startId) { 86 return super.onStartCommand(intent, flags, startId); 87 } 88 89 /** 90 * 销毁服务时,调用此方法 91 */ 92 @Override 93 public void onDestroy() { 94 super.onDestroy(); 95 } 96 }
1 package com.ahu.lichang.recorderservice; 2 3 import android.content.Intent; 4 import android.support.v7.app.AppCompatActivity; 5 import android.os.Bundle; 6 import android.view.View; 7 8 public class MainActivity extends AppCompatActivity { 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_main); 14 } 15 16 public void click(View view){ 17 Intent intent = new Intent(this,RecorderService.class); 18 startService(intent); 19 } 20 }
1 package com.ahu.lichang.recorderservice; 2 3 import android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 7 /** 8 * Created by ahu_lichang on 2017/3/24. 9 */ 10 11 public class RecorderReceiver extends BroadcastReceiver { 12 @Override 13 public void onReceive(Context context, Intent intent) { 14 //开机启动时,开启录音服务 15 Intent i = new Intent(context,RecorderService.class); 16 context.startService(i); 17 } 18 }
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.ahu.lichang.recorderservice"> 4 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 5 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 6 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 7 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 8 <uses-permission android:name="android.permission.RECORD_AUDIO"/> 9 10 <application 11 android:allowBackup="true" 12 android:icon="@mipmap/ic_launcher" 13 android:label="@string/app_name" 14 android:supportsRtl="true" 15 android:theme="@style/AppTheme"> 16 <activity android:name=".MainActivity"> 17 <intent-filter> 18 <action android:name="android.intent.action.MAIN" /> 19 20 <category android:name="android.intent.category.LAUNCHER" /> 21 </intent-filter> 22 </activity> 23 24 <receiver android:name=".RecorderReceiver"> 25 <intent-filter> 26 <!--开机启动--> 27 <action android:name="android.intent.action.BOOT_COMPLETED"/> 28 </intent-filter> 29 </receiver> 30 31 <service android:name=".RecorderService"> 32 </service> 33 </application> 34 35 </manifest>
服务的两种开启方式:
1、startService方式开启服务
服务启动之后,跟启动他的组件没有关系。该方法启动的服务所在进程属于服务进程。
2、bindService方式开启服务(重点)
bindService绑定服务、unBindService解除绑定的服务;
服务是在被绑定的时候被创建,调用oncreate、onbind方法;
服务只能被绑定一次;
服务只能被解除一次,解除绑定的时候调用onUnbind、onDestrory方法,如果多次解除绑定会抛出异常;
推荐的方式:跟他启动的组件同生共死,该方法启动的服务所在进程不属于服务进程
startService:开启并创建一个服务,服务长期运行在后台;
bindService:绑定服务,可以调用服务里面的方法;
unBindService:解除服务,停止服务里面的方法;
stopService:停止服务,销毁服务对象;
为什么要引入bindservice的API?
为了调用服务中的业务逻辑方法。
绑定服务调用服务方法的过程
通过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();
绑定服务抽取接口(重点)
接口(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();
}
案例:在activity里面不能直接去调用服务中的方法,所以要想调用服务里面的方法必须通过一个中间人,通过中间人的牵线才能去调用服务里的方法。
PublicBusiness接口是服务LeaderService的接口类,对象暴露出中间人的业务逻辑方法QianXian(),隐藏了中间人的其他方法daMaJiang()。
1 public interface PublicBusiness { 2 3 void QianXian(); 4 }
1 public class LeaderService extends Service { 2 3 @Override 4 public IBinder onBind(Intent intent) { 5 // 返回一个Binder对象,这个对象就是中间人对象 6 return new ZhouMi(); 7 } 8 9 class ZhouMi extends Binder implements PublicBusiness{ 10 public void QianXian(){ 11 banZheng();//banZheng()方法是服务中的方法 12 } 13 14 public void daMaJiang(){ 15 System.out.println("陪李处打麻将"); 16 } 17 } 18 19 public void banZheng(){ 20 System.out.println("李处帮你来办证"); 21 } 22 }
1 public class MainActivity extends Activity { 2 3 private Intent intent; 4 private MyServiceConn conn; 5 PublicBusiness pb; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_main); 11 intent = new Intent(this, LeaderService.class); 12 conn = new MyServiceConn(); 13 //绑定领导服务 14 bindService(intent, conn, BIND_AUTO_CREATE); 15 } 16 17 public void click(View v){ 18 //调用服务的办证方法 19 pb.QianXian(); 20 } 21 22 class MyServiceConn implements ServiceConnection{ 23 24 //连接服务成功,此方法调用 25 @Override 26 public void onServiceConnected(ComponentName name, IBinder service) { 27 // TODO Auto-generated method stub 28 pb = (PublicBusiness) service; 29 } 30 31 @Override 32 public void onServiceDisconnected(ComponentName name) { 33 // TODO Auto-generated method stub 34 35 } 36 37 } 38 39 }
两种启动方式混合使用
用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,可是音乐服务中的方法,需要被前台activity所调用,所以需要混合启动音乐服务。
//混合调用
//为了把服务所在进程变成服务进程
startService(intent);//先开启服务进程------------>只是在之前的程序中多了这句代码!!!
//为了拿到中间人对象
bindService(intent, new MusicServiceConn(), BIND_AUTO_CREATE);//拿到中间人对象
先startService,后bindService,销毁时先unbind,在stop。
绑定服务的应用场景
1、需要在后台运行一定的业务逻辑,而且需要与服务器端交互数据,都是写在服务里面的。
2、天气预报、股票行情软件;
利用服务注册广播接收者
操作频繁的广播事件,如果只是在清单配置文件配置,是不生效的。需要使用代码注册才能生效;
步骤:
// 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);
远程服务aidl的写法(重点)
本地服务:写在自己的应用程序的工程里的服务 ,使用自己应用程序的进程运行这个服务;
远程服务:写在别的应用程序的工程里的服务,使用别的应用程序的进程运行这个服务(安装在同一个手机上的应用程序);
IPC: Inter Process Communication(进程间的通讯);
aidl: Android Interface definition language 安卓接口定义语言;安卓接口语言作用是用于跨进程间通信。
aidl的接口类里面不需要public 、protected、private 等修饰符,默认是公开共享;
步骤:
1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法
2、让服务中的中间人实现了服务的接口类
3、修改并拷贝接口文件
4、在本地服务的工程中的activity里,绑定服务
5、通过接口调用远程服务的方法