什么是服务?
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、通过接口调用远程服务的方法