引言
Service的主要作用,在 Android 开发中,Service 是一种用于在后台执行操作的组件。与 Activity 不同,Service 并不提供用户界面,而是专注于处理长时间运行的任务或执行需要在后台进行的工作。Activity生活在前台,而Service生活在后台
使用场景
-
当需要执行可能需要较长时间才能完成的任务(例如网络请求、文件下载等),或者需要持续运行的任务(记录日志等),使用 Service 可以避免阻塞主线程(UI 线程),从而保证应用的响应性。
-
即使应用程序不在前台显示,Service 也可以继续在后台运行。这对于需要持续更新数据的应用来说非常有用,比如音乐播放器即使退出了主界面也能继续播放音乐。(但如果不是前台Service,则随时会被回收)
TIP: 虽然Service运行在后台,但实际上Service并不会自动开启新线程,所有的代码都是默认运行在主线程当中的 。也就是说,需要在Service的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况(导致停止响应)。
Service的创建与使用
我们可以直接在Android Studio中创建Service

其中Exported属性表示是否将这个Service暴露给 外部其他程序访问,Enabled属性表示是否启用这个Service
java
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
使用Service 启用Service与启用新的Activity一样,都需要Intent的支持。比如:
java
Intent intent = new Intent(this, MyService.class);
startService(intent);
但有不同的是,Service支持暂停
java
Intent intent = new Intent(this, MyService.class);
stopService(intent);
TIP: 从Android 8.0系统开始,应用的后台功能被大幅削减。现在只有当应用保持在前台可见状态的情况下,Service才能保证稳定运行,一旦应用进入后台之后,Service随时都有可能被系统回收。 之所以做这样的改动,是为了防止许多恶意的应用程序长期在后台占用手机资源,从而导致手机变得越来越卡。当然,如果真的非常需要长期在后台执行一些任务,可以使用前台Service或者WorkManager
(听说早期有APP把自己缩小为一个像素来保活)
Service与Activity通信
我们在extends Service
后,会强制要求实现onBind
。而onBind
也正是实现Service与Activity通信的基础。onBind
的方法签名如下所示
java
@Override
public IBinder onBind(Intent intent) {
return new MyBind();
}
主要是接收一个Intent
,响应一个IBinder
。此时我们可以编写一个类实现IBinder
接口或继承Binder
。然后在绑定后返回。同时,在Service与Activity绑定时一共需要两个类,一个ServiceConnection
类以及一个IBinder
类
ServiceConnection
该类主要是在连接成功与断开时使用。具有两个主要方法 ServiceConnected(ComponentName name, IBinder service)
,onServiceDisconnected(ComponentName name)
- 前者,当 Activity 与 Service 成功绑定后调用,可以通过 service 参数获取到 Service 的通信接口。
- 后者,当连接意外断开时调用(如 Service 崩溃或被杀死)。
IBinder
IBinder
是一个接口,它是 Android 中进程间通信 (IPC) 的基础 。在 Service 与 Activity 绑定的场景中,Service 需要通过IBinder
向 Activity 提供交互接口。他是交互的实际执行对象。 ,通常我们不选择implements IBinder
接口,而是选择extends Binder
。之后编写自己的方法。
Service与Activity的绑定
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
用于两者的绑定
unbindService(mConnection);
用于两者的解绑 下方是部分示例代码
java
public class MyService extends Service {
// 自定义Binder类,继承自Binder并实现我们需要的方法
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
// 返回当前Service的实例,这样Activity就能调用Service中的公共方法
MyService getService() {
return MyService.this;
}
// 也可以直接在这里定义供Activity调用的方法
public void doSomething() {
// 实现具体功能
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// Service中其他的公共方法,Activity可以通过LocalBinder获取Service实例后调用
public void publicMethod() {
// 实现具体功能
}
}
java
public class MainActivity extends AppCompatActivity {
private MyService mService;
private boolean mBound = false;
// 实现ServiceConnection接口
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// 当与Service的连接建立后,此方法会被调用
// 通过IBinder获取Service实例
MyService.LocalBinder binder = (MyService.LocalBinder) service;
mService = binder.getService();
mBound = true;
// 连接成功后可以立即调用Service中的方法
if (mBound) {
mService.publicMethod();
// binder.doSomething()
}
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
// 当与Service的连接意外断开时(如Service崩溃或被杀死),此方法会被调用
mBound = false;
}
};
// ...
@Override
protected void onStart() {
super.onStart();
// 绑定Service
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解除绑定
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
// Activity中的方法,调用Service的功能
public void callServiceMethod(View view) {
if (mBound) {
mService.doSomething();
}
}
// ...
}
在上面的示例中,MainActivity
启动后,执行onStart
。绑定并启动Service。同时通过onBind()
获得IBinder
对象,执行onServiceConnected(ComponentName, IBinder)
获得IBinder
对象,就可以执行IBinder中的方法了。断开则是执行去onServiceDisconnected()
onBind()
-> onServiceConnected()
-> onServiceDisconnected()
Service的生命周期
类似于Activity,Service也有自己的生命周期。不过Service的生命周期相对来说比较复杂。主要有两种启用方式,startService
与bindService
。具体执行流程可以如下图所示。
text
onCreate()
↓
┌────────────────┐
│ 启动方式? │───────────┐
└───────┬────────┘ │
↓ │
┌───────────────────────┐ ↓
│ startService() │ bindService()
│ ┌─────────────────┐ │ ┌────────────┐
│ │ onStartCommand()│ │ │ onBind() │
│ └─────────────────┘ │ └──────┬─────┘
│ ↓ │ ↓
│ 运行中 Service │ 客户端绑定
│ ↓ │ ↓
│ stopService()/ │ unbindService()
│ stopSelf() │ ↓
└───────────┬───────────┘ ┌─────────────┐
│ │ onUnbind() │
│ └──────┬──────┘
│ ↓
└───────────┬───────────┘
↓
onDestroy()
-
每调用一次
startService()
方法,onStartCommand()
就会执行一次,但实际上每个Service只会存在一个实例 。所以不管你调用了多少次startService()方法,只需调用一次stopService()
或stopSelf()
方法,Service就会停止。在这一类启动方法下- Service 会在后台无限期运行,直到被系统终止 或调用stopService()
/stopSelf()
。 -
当调用
bindService()
时,Service
与绑定的组件(如Activity
)生命周期绑定 ,组件解除绑定时 Service 会被销毁。 -
当两种启动方式都使用呢,根据Android系统的机制,一个Service只要被启动或者被绑定了之后,就会处于运行状态 ,必须要让以上两种条件同时不满足 ,Service才能被销毁。所以,这种情况下要同时调用
stopService()
和unbindService()
方法,onDestroy()
方法才会执行。
TIP:每个Service只会存在一个实例,其是单例的。所以对于同一个Service,onCreate()与onDestory()只会执行一次。