关于Service
Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
Service分类
Service的工作状态分为两种类型:
启动:主要用于执行后台计算。
绑定:主要用于其他组件和Service进行交互。
注意: 服务在其托管进程的主线程中运行,它既不创建自己的线程,也不再单独的进程中运行(除非另行指定)。这意味着,如果服务将执行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或联网),则应在服务内创建新线程来完成这项工作。通过使用单独的线程,可以降低发生“应用无响应”(ANR) 错误的风险,而应用的主线程仍可继续专注于运行用户与 Activity 之间的交互。
创建Service
创建Service时必须重写它的几个回调方法,案例如下:
public class CustomService extends Service{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
回调方法说明:
- onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。
- onStartCommand()
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用 stopSelf() 或 stopService() 来停止服务。(如果您只想提供绑定,则无需实现此方法。)
- onBind()
当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。
- onUnbind()
当前Service被解绑时,系统将调用此方法。
- onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。
AndroidManifest.xml配置
Service与其他组件(如:Activity)一样都需要在AndroidManifest进行注册,
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sample.app">
<application
......
<!--注册Service-->
<service
android:name=".CustomService"
android:exported="false" />
</application>
</manifest>
android:name 属性是唯一必需的属性,用于指定服务的类名。
android:exported 属性并将其设置为 “false”,确保服务仅适用于您的应用。这可以有效阻止其他应用启动您的服务。
启动Service
调用 startService() 启动Service
Intent mIntent = new Intent(this, CustomService.class)
startService(mIntent);
Android O(v8.0)适配
Android O(v8.0)版本不在允许启动后台Service了,所以在8.0及以上版本中通过startForegroundService函数启动一个前台服务。
Intent mIntent = new Intent(this, CustomService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(mIntent);
} else {
startService(mIntent);
}
另外还需要在Service的onCretae方法中调用发送一个通知,否则会报ANR
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel mChannel = new NotificationChannel(this.getPackageName(), getResources().getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
mNotificationManager.createNotificationChannel(mChannel);
Notification mNotification = new Notification.Builder(getApplicationContext(), this.getPackageName()).build();
startForeground(-1, mNotification);
}
停止Service
stopService(new Intent(this, CustomService.class));
通过 startService() 启动该Service,从启动到停止Log输出如下:
03-16 10:38:12.959 21096-21096/com.sample.app E/CustomService: ----- onCreate()
03-16 10:38:12.960 21096-21096/com.sample.app E/CustomService: ----- onStartCommand()
03-16 10:38:15.192 21096-21096/com.sample.app E/CustomService: ----- onDestroy()
绑定Service
调用 bindService() 绑定一个Service,定义Service代码如下:
public class CustomService extends Service {
private static final String TAG = CustomService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "----- onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "----- onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "----- onUnbind()");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "----- onDestroy()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "----- onBind()");
return new CustomBind();
}
class CustomBind extends Binder {
public CustomService getService() {
return CustomService.this;
}
}
}
通过 bindService() 绑定一个Service时,需要定义一个 Binder 的子类,如上面代码中:
class CustomBind extends Binder {
public CustomService getService() {
return CustomService.this;
}
}
这样就可以拿到一个Service对象,在Activity中通过ServiceConnection接口来取得建立连接与连接意外丢失的回调
public class BindServiceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通过bindService绑定Service
Intent mIntent = new Intent(this, CustomService.class);
bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Activity销毁时解绑Service
unbindService(mServiceConnection);
}
// 在Activity中,我们通过ServiceConnection接口来取得建立连接与连接意外丢失的回调
ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 建立连接,获取服务的操作对象
CustomService.CustomBind mBind = (CustomService.CustomBind) service;
mBind.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 连接断开
}
};
}
解绑Service
unbindService(mServiceConnection);
该Activity由创建到销毁Service中的Log输出如下:
03-16 10:15:27.361 17920-17920/com.sample.app E/CustomBindService: ----- onCreate()
03-16 10:15:27.361 17920-17920/com.sample.app E/CustomBindService: ----- onBind()
03-16 10:15:30.211 17920-17920/com.sample.app E/CustomBindService: ----- onUnbind()
03-16 10:15:30.211 17920-17920/com.sample.app E/CustomBindService: ----- onDestroy()
总结
- 两种启动方式都可在Intent中携带Bundle对象,向Service中传递一个Bundle对象。
- 通过 startService() 启动服务时,onBind() 和 onUnbind() 这两个生命周期是不会被回调的,通过 bindService() 绑定一个Service时,onStartCommand() 这个生命周期是不会被回调的。
Service的生命周期
Service的调用方式不一样,所以调用的生命周期也是有区别的
在Service的生命周期里,常用的有:
4个手动调用的方法
方法 | 作用 |
---|---|
startService() | 启动Service |
stopService() | 停止Service |
bindService() | 绑定Service |
unbindService() | 解绑Service |
5个内部自动调用的方法
方法 | 作用 |
---|---|
onCreate() | 创建Service |
onStartCommand() | 启动Service |
onBind() | 绑定Service |
onUnbind() | 解绑Service |
onDestroy | 销毁Service |