一. 本地Service

1. 简介

这是最普通、最常用的后台服务Service。

2. 使用步骤

步骤1:新建子类继承Service类,在AndroidManifest.xml里注册Service。(需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法)

步骤2:构建用于启动Service的Intent对象。

步骤3:调用startService()启动Service、调用stopService()停止服务。

3. 实例

① 新建子类继承Service类,在AndroidManifest.xml里注册Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MyService extends Service {
//日志
private static final String TAG = MyService.class.getSimpleName();

//音乐播放器
private MediaPlayer mediaPlayer;

@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"onCreate");

//初始化操作
mediaPlayer = MediaPlayer.create(this,R.raw.bg_music);
mediaPlayer.setVolume(0.8f,0.8f);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStart");

//开始播放
mediaPlayer.start();

return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();

//结束播放
mediaPlayer.stop();

Log.d(TAG,"onDestroy");
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="swu.xl.service_local">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service android:name=".MyService"/>

</application>

</manifest>

② 构建用于启动Service的Intent对象

1
Intent intent = new Intent(this, MyService.class);

③ 调用startService()启动Service、调用stopService()停止服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onClick(View v) {

Intent intent = new Intent(this, MyService.class);

switch (v.getId()){
case R.id.start:
startService(intent);
break;
case R.id.stop:
stopService(intent);
break;
}
}

④ 运行结果

1
2
3
4
5
6
//点击开始按钮---开始播放音乐
2020-05-25 10:51:33.071 21236-21236/swu.xl.service_local D/MyService: onCreate
2020-05-25 10:51:33.096 21236-21236/swu.xl.service_local D/MyService: onStart

//点击停止按钮---停止播放音乐
2020-05-25 10:51:39.673 21236-21236/swu.xl.service_local D/MyService: onDestroy

4. Androidmanifest里Service的常见属性说明

属性 说明 备注
android:name Service的类名
android:label Service的名字 若不设置,默认为Service类名
android:icon Service的图标
android:permission 申明此Service的权限 有提供了该权限的应用才能控制或连接此服务
android:process 表示该服务是否在另一个进程中运行(远程服务) 不设置默认为本地服务;remote则设置成远程服务
android:enabled 系统默认启动 true:Service 将会默认被系统启动;不设置则默认为false
android:exported 该服务是否能够被其他应用程序所控制或连接 不设置默认此项为 false

二. 可通信的Service

1. 简介

上面介绍的Service是最基础的,但只能单机使用,即无法与Activity通信。

接下来将在上面的基础用法上,增设“与Activity通信”的功能,即使用绑定Service服务。

2. 使用步骤

步骤1:新建子类继承Service类,在AndroidManifest.xml里注册Service。并新建一个子类继承自Binder类、获取Service实例,进而实现Activity与Service的通信。

步骤2:构建用于启动Service的Intent对象。以及监听绑定的ServiceConnection对象。

步骤3:调用bindService()启动Service、调用unbindService()停止服务。

3. 实例

① 新建子类继承Service类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@SuppressLint("Registered")
public class MyService extends Service {

//日志
private static final String TAG = MyService.class.getSimpleName();

//音乐播放器
private MediaPlayer mediaPlayer;
//音乐音量
private float volume = 0.8f;

//Binder
private IBinder iBinder = new LocalBinder();

@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"onCreate");

//初始化操作
mediaPlayer = MediaPlayer.create(this,R.raw.bg_music);
mediaPlayer.setVolume(volume,volume);
//开始播放
mediaPlayer.start();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStart");

return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();

//结束播放
mediaPlayer.stop();

Log.d(TAG,"onDestroy");
}

@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind");
return iBinder;
}

@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG,"unbind");
return super.onUnbind(intent);
}

//获取Service实例
public class LocalBinder extends Binder {
MyService getService(){
return MyService.this;
}
}

//获取当前音乐的进度
public float getVolume(){
return volume;
}
}

② 构建Intent对象和ServiceConnection对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//ServiceConnection
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//在Activity与Service建立关联的时候调用

//1.强制转化
MyService.LocalBinder localBinder = (MyService.LocalBinder) service;

//2.获取Service实例
MyService myService = localBinder.getService();

//3.通信
Toast.makeText(myService, "当前的音量:"+myService.getVolume(), Toast.LENGTH_SHORT).show();
}

@Override
public void onServiceDisconnected(ComponentName name) {
//在Activity与Service解除关联的时候调用
}
};

③ 调用bindService()启动Service、调用unbindService()停止服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

//ServiceConnection
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//在Activity与Service建立关联的时候调用

//1.强制转化
MyService.LocalBinder localBinder = (MyService.LocalBinder) service;

//2.获取Service实例
MyService myService = localBinder.getService();

//3.通信
Toast.makeText(myService, "当前的音量:"+myService.getVolume(), Toast.LENGTH_SHORT).show();
}

@Override
public void onServiceDisconnected(ComponentName name) {
//在Activity与Service解除关联的时候调用
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button start = findViewById(R.id.start);
Button stop = findViewById(R.id.stop);

start.setOnClickListener(this);
stop.setOnClickListener(this);
}

@Override
public void onClick(View v) {

//意图
Intent intent = new Intent(this, MyService.class);

switch (v.getId()){
case R.id.start:
//绑定服务
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
break;
case R.id.stop:
//解绑服务
unbindService(serviceConnection);
break;
}
}
}

④ 运行结果

1
2
3
4
5
6
//点击start按钮,音乐响起来,弹出Toast显示当前音量
2020-05-25 13:05:48.925 10778-10778/swu.xl.service_connection D/MyService: onCreate
2020-05-25 13:05:48.940 10778-10778/swu.xl.service_connection D/MyService: onBind
//点击stop按钮,音乐关闭
2020-05-25 13:05:49.963 10778-10778/swu.xl.service_connection D/MyService: unbind
2020-05-25 13:05:49.966 10778-10778/swu.xl.service_connection D/MyService: onDestroy

4. bindService的第三个参数标志位

BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service。

这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。

三. 前台Service

1. 简介

前台Service在下拉通知栏有显示通知,但后台Service没有。

前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收。

2. 使用步骤

用法很简单,只需要在原有的Service类对onCreate()方法进行稍微修改。

3. 实例

① 新建子类继承Service类,在AndroidManifest.xml里注册Service并添加前台权限,并在onCreate中添加通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class MyService extends Service {
//日志
private static final String TAG = MyService.class.getSimpleName();

//音乐播放器
private MediaPlayer mediaPlayer;

@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"onCreate");

//初始化操作
mediaPlayer = MediaPlayer.create(this,R.raw.bg_music);
mediaPlayer.setVolume(0.8f,0.8f);

String CHANNEL_ONE_ID = "CHANNEL_ONE_ID";
String CHANNEL_ONE_NAME= "CHANNEL_ONE_ID";
NotificationChannel notificationChannel= null;
//进行8.0的判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel= new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(notificationChannel);
}

//添加下列代码将后台Service变成前台Service
//构建"点击通知后打开MainActivity"的Intent对象
Intent notificationIntent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);

//新建Builder对象
Notification.Builder builder = new Notification.Builder(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ONE_ID);
}
builder.setContentTitle("前台服务通知的标题");//设置通知的标题
builder.setContentText("前台服务通知的内容");//设置通知的内容
builder.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标
builder.setContentIntent(pendingIntent);//设置点击通知后的操作

Notification notification = builder.build();//将Builder对象转变成普通的notification
notification.flags|= Notification.FLAG_NO_CLEAR;
startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStart");

//开始播放
mediaPlayer.start();

return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();

//结束播放
mediaPlayer.stop();

Log.d(TAG,"onDestroy");
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="swu.xl.service_local">

<!--添加前台权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service android:name=".MyService"/>

</application>

</manifest>

② 构建用于启动Service的Intent对象

1
Intent intent = new Intent(this, MyService.class);

③ 调用startService()启动Service、调用stopService()停止服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onClick(View v) {

Intent intent = new Intent(this, MyService.class);

switch (v.getId()){
case R.id.start:
startService(intent);
break;
case R.id.stop:
stopService(intent);
break;
}
}

④ 运行结果

4. Android 8.0中使用Notification

参考:在Android 8.0中使用Notification中发生 Bad notification for startForeground错误

四. 远程Service

参考:Android多进程

参考文章:Android:远程服务Service(含AIDL & IPC讲解)

源码

Service

参考文章

Android:(本地、可通信的、前台、远程)Service使用全面介绍