Service基本概念
Android Service
是一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可以由其他应用组件启动(如Activity),一旦启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信(IPC)。
Service形式
在 Android 中,Service 主要有三种形式,每种形式适用于不同的场景。
1. Started Service(启动式服务)
- 特点:
- 通过
startService()
启动,独立运行,与启动组件无直接关联。 - 需手动调用
stopService()
或stopSelf()
终止。 - 适合执行独立任务(如文件下载、音乐播放)。
- 通过
- 生命周期:
onCreate() → onStartCommand() → [运行中] → onDestroy()
-
关键方法:
-
onCreate()
Service 首次创建时调用(类似 Activity 的 onCreate),用于初始化资源(如线程池、广播接收器)。 -
onStartCommand(Intent intent, int flags, int startId)
每次调用startService()
时触发,传入启动 Intent。返回值决定 Service 被系统终止后的重启策略:- START_STICKY:重启 Service,
intent
为 null(适用于媒体播放)。 - START_NOT_STICKY:不重启(适用于一次性任务,如文件下载)。
- START_REDELIVER_INTENT:重启并重新传递最后一个
intent
。
- START_STICKY:重启 Service,
-
onDestroy()
Service 销毁前调用,需释放资源(如停止线程、注销广播接收器)。
-
-
代码示例:
public class MyService extends Service {
private volatile boolean isRunning = true;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 10; i++){
if(!isRunning){
break;
}
Log.d("MyService", "Service is running: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
// 打印完成后停止服务
stopSelf();
}
}).start();
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
isRunning = false;
Log.d("MyService", "Service is destroyed");
}
}
2. Bound Service(绑定式服务)
-
特点:
- 通过
bindService()
绑定到组件(如 Activity),允许组件与 Service 交互。 - 多个组件可同时绑定,最后一个组件解绑时 Service 销毁。
- 适合提供跨组件功能(如获取系统服务、数据共享)。
- 通过
-
生命周期
onCreate() → onBind() → [绑定中] → onUnbind() → onDestroy()
- 关键方法
- onBind(Intent intent)
首次绑定时调用,返回IBinder
接口供组件通信。 - onUnbind(Intent intent)
最后一个组件解绑时触发,默认返回false
。若返回true
,下次绑定时会触发onRebind()
。 - onRebind(Intent intent)
在onUnbind()
返回true
后,再次绑定时调用。
- onBind(Intent intent)
- 代码示例
public class MyBoundService extends Service {
private final IBinder binder = new MyLocalBinder();
private int count = 0;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MyLocalBinder extends Binder {
MyBoundService getService() {
return MyBoundService.this;
}
}
public void incrementCount() {
count++;
Log.d("MyBoundService", "Current count: " + count);
}
public int getCount() {
return count;
}
}
public class MainActivity extends AppCompatActivity {
private MyBoundService myBoundService;
private boolean isServiceBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyBoundService.MyLocalBinder binder = (MyBoundService.MyLocalBinder) service;
myBoundService = binder.getService();
isServiceBound = true;
// 显示当前计数
TextView countTextView = findViewById(R.id.count_text_view);
countTextView.setText("Count: " + myBoundService.getCount());
}
@Override
public void onServiceDisconnected(ComponentName name) {
isServiceBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button incrementButton = findViewById(R.id.increment_button);
Button unbindButton = findViewById(R.id.unbind_button);
TextView countTextView = findViewById(R.id.count_text_view);
incrementButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isServiceBound) {
myBoundService.incrementCount();
countTextView.setText("Count: " + myBoundService.getCount());
}
}
});
unbindButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
isServiceBound = false;
}
});
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyBoundService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (isServiceBound) {
unbindService(serviceConnection);
isServiceBound = false;
}
}
}
3. Foreground Service(前台服务)
-
特点:
- 执行用户可感知的任务,必须显示通知(如音乐播放器、导航)。
- 优先级高,系统不易回收,适合持续运行的任务。
-
启动步骤:
- 创建通知渠道(Android 8.0+)。
- 构建通知并调用
startForeground(NOTIFICATION_ID, notification)
。
4. 混合模式(Started + Bound)
-
特点:
- 同时支持
startService()
和bindService()
。 - 需同时管理两种生命周期,适合既需要独立运行又需要交互的场景。
- 同时支持
-
典型场景:
- 启动服务执行后台任务,同时允许 Activity 绑定获取进度。
5. 总结对比
类型 | 启动方式 | 生命周期 | 通信方式 | 典型场景 |
---|---|---|---|---|
Started Service | startService() | 独立运行,需手动停止 | 广播、回调 | 音乐播放、文件下载 |
Bound Service | bindService() | 依赖绑定组件 | IBinder 接口 | 数据共享、系统服务代理 |
Foreground Service | startForeground() | 高优先级,必须显示通知 | 同 Started/Bound | 导航、实时位置跟踪 |
IntentService
IntentService
是 Android 提供的一个抽象类,继承自 Service
,用于简化异步任务处理。它在单独的工作线程中执行任务,并在所有请求处理完成后自动停止,适合处理一次性的后台任务(如网络请求、文件操作)。
- 自动创建工作线程:所有
onHandleIntent()
中的代码在后台线程执行,避免 ANR。 - 任务队列处理:通过
HandlerThread
和Looper
实现任务排队,按顺序执行。 - 自动停止服务:所有任务完成后,
IntentService
会自动调用stopSelf()
。 - 简化的生命周期:只需实现
onHandleIntent()
,无需手动管理线程和停止逻辑。
1. 基本用法
创建子类并实现 onHandleIntent()
:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService"); // 工作线程名称,用于调试
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 在后台线程执行耗时任务
if (intent != null) {
String action = intent.getAction();
if ("ACTION_DOWNLOAD".equals(action)) {
downloadFile(intent.getStringExtra("url"));
}
}
}
private void downloadFile(String url) {
// 文件下载逻辑(已在后台线程,无需额外线程)
}
}
在 Manifest 中注册:
<service android:name=".MyIntentService"
android:enabled="true"
android:exported="false"/>
启动服务:
Intent intent = new Intent(this, MyIntentService.class);
intent.setAction("ACTION_DOWNLOAD");
intent.putExtra("url", "https://example.com/file.zip");
startService(intent);
2. 核心实现
-
工作线程与消息循环
IntentService
在onCreate()
中创建HandlerThread
和ServiceHandler
,用于处理任务:@Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
-
任务处理流程
startService(intent)
触发onStartCommand()
,将intent
封装为消息发送到工作线程。- 工作线程通过
ServiceHandler
接收消息,调用onHandleIntent()
处理任务。 - 所有任务完成后,自动调用
stopSelf(msg.arg1)
停止服务。
-
任务队列
多个intent
会按顺序在工作线程执行,同一时间只处理一个任务。
3. 总结对比
特性 | IntentService | 普通 Service |
---|---|---|
线程环境 | 自动在后台线程执行任务 | 默认在主线程,需手动创建子线程 |
任务处理 | 按顺序处理多个任务 | 需手动管理多线程并发 |
自动停止 | 任务完成后自动停止 | 需手动调用 stopSelf() 或 stopService() |
适用场景 | 独立、顺序执行的后台任务(如文件下载) | 持续运行的服务(如音乐播放) |
-
不支持并发:
IntentService
同一时间只处理一个任务,若需并发,可使用Service + ExecutorService
。 -
无法直接通信:任务执行结果无法直接返回给 Activity,需通过广播或回调。
java
// 在 onHandleIntent() 中发送广播 Intent resultIntent = new Intent("DOWNLOAD_COMPLETED"); resultIntent.putExtra("result", "success"); sendBroadcast(resultIntent);
-
已过时(Android 8.0+) :推荐使用
WorkManager
替代,支持任务调度、重试和电量优化。