简介
服务(Service)是Android中后台运行的程序,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖于任何用户界面,即使程序被切换到后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。
不过需要注意的是,服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。
Service使用
创建服务
右键包 New -> Service - Service弹出如下窗口。
通过这种形式会自动在AndroidManifest.xml中创建。
创建的Service完整代码如下:
package com.example.androidlearn.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.LongDef;
public class MyService extends Service {
private static final String TAG = "MyService";
private int count = 0;
private MyBinder myBinder = new MyBinder();
public MyService() {
}
class MyBinder extends Binder{
public void methodInBinder(){
Log.d(TAG, "instance initializer: mybinder");
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return myBinder;
}
// 服务创建时候调用
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: 创建服务");
}
// 服务启动时候调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: 启动服务");
return super.onStartCommand(intent, flags, startId);
}
// 服务销毁的时候调用
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: 销毁服务");
super.onDestroy();
}
}
继承自Service类,说明这是一个服务。onBind是Service中唯一一个抽象方法,用来返回一个Ibinder代理对象,它是程序组件和Service通信用的。
Service里重写了onCreate()、onStartCommand()、和onDestory()方法。
- onCreate()方法是在服务创建的时候被调用。
- onStartCommand()是在服务启动的时候调用。
- onDestory()是在服务销毁的时候调用。
服务启动
布局文件就是两个按钮,一个启动Service的按钮,一个停止Service的按钮
## MainActivity.java
public class ServiceMainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "ServiceMainActivity";
private MyService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.service_main_activity);
Button startServiceBtn = findViewById(R.id.start_service_btn);
Button stopServiceBtn = findViewById(R.id.stop_service_btn);
startServiceBtn.setOnClickListener(this);
stopServiceBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_service_btn:
Intent startServiceIntent = new Intent(this, MyService.class);
startService(startServiceIntent);
break;
case R.id.stop_service_btn:
Intent stopServiceIntent = new Intent(this, MyService.class);
stopService(stopServiceIntent);
break;
}
}
}
可以看到,这里在onCreate()方法中分别获取到了Start Service按钮和Stop Service按钮的实例,并给它们注册了点击事件。然后在Start Service按钮的点击事件里,我们构建出了一个Intent 对象,并调用startService()方法来启动MyService这个服务。在Stop Serivce按钮的点击事件里,我们同样构建出了一个Intent对象,并调用stopService()方法来停止MyService这个服务。startService()和 stopService()方法都是定义在Context类中的,所以我们在活动里可以直接调用这两个方法。注意,这里完全是由活动来决定服务何时停止的,如果没有点击Stop Service按钮,服务就会一直处于运行状态。那服务有没有什么办法让自已停止下来呢?当然可以,只需要在MyService的任何一个位置调用stopSelf()方法就能让这个服务停止下来了。
点击一次启动服务按钮,再点击一次停止服务的按钮打印日志如下图:
服务在没有创建的时候,点击启动服务按钮,服务被创建,onCreate方法被调用,然后执行onStartCommand方法。再次点击启动服务按钮,onCrate方法不执行,即onCreate方法只是在服务没有创建的时候,启动服务时才会被调用。onStartCommand每次启动的时候都会被调用。
绑定服务
虽然服务是在活动里启动的,但在启动了服务之后,活动与服务基本就没有什么关系了。
当程序通过startService()和 stopService()启动、关闭 Service 时,Service 与访问者之间基本上不存在太多的关联,因此Service和访问者之间也无法进行通信、交换数据。
如果 Service 和访问者之间需要进行方法调用或交换数据,则应该使用bindService)和unbindService()方法启动、关闭Service。Context的bindService)方法的完整方法签名为: bindService(Intent service, ServiceConnectionconn, int flags),该方法的三个参数解释如下。
- service:该参数通过Intent指定要启动的Service。
- conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况**。当访问者与Service之间连接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)法**; 当Service所在的宿i程由于异常中止或其他原因终止,导致该Service与访问者之间断开连接时回调该ServiceConnection 对象的 onServiceDisconnected(ComponentName)。
- flags:指定绑定时是否自动创建Service (如果Service还未创建)。该参数可指定为0 (不自动创建)或BIND AUTO_CREATE (自动创建)。
注意: 当调用者主动通过unBindService()方法断开与Service 的连接时,ServiceConnection对象的 onServiceDisconnected (ComponentName)方法并不会被调用。
注意到 ServiceConnection 对象的 onServiceConnected()方法中有一个IBinder 对象参数,该对象即可实现与被绑定Service之间的通信。
当开发 Service 类时,该 Service 类必须提供一个 IBinder onBind(Intent intent)方法,在绑定本地Service的情况下, onBind(Intent intent)方法所返回的IBinder 对象将会传给ServiceConnection对象里onServiceConnected(ComponentName name, IBinder service)法的 service参数,这样ii者就通过该IBinder 对象与Service 进行通信了。
通过在onBind方法里返回一个IBinder代理通信对象。
在Service类中,创建内部类继承IBinder。然后在onBind方法中返回。
完整的Service代码如下:
public class MyService extends Service {
private static final String TAG = "MyService";
private MyBinder myBinder = new MyBinder();
public MyService() {
}
class MyBinder extends Binder{
public void methodInBinder(){
Log.d(TAG, "Binder方法");
}
}
// 服务绑定的时候被调用
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return myBinder;
}
// service链接被断开始调用
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind: service断开链接时调用");
return super.onUnbind(intent);
}
// 服务创建时候调用
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: 创建服务");
}
// 服务启动时候调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: 启动服务");
return super.onStartCommand(intent, flags, startId);
}
// 服务销毁的时候调用
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: 销毁服务");
super.onDestroy();
}
}
创建布局文件 一个绑定服务的按钮和一个取消绑定服务的按钮,布局代码不再展示
MainActivity代码如下:
package com.example.androidlearn.service;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import com.example.androidlearn.R;
public class ServiceMainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "ServiceMainActivity";
private MyService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.service_main_activity);
Button bindServiceBtn = findViewById(R.id.bind_service_btn);
Button unBindServiceBtn = findViewById(R.id.unbind_service_btn);
bindServiceBtn.setOnClickListener(this);
unBindServiceBtn.setOnClickListener(this);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: 服务绑定成功");
myBinder = (MyService.MyBinder) service;
myBinder.methodInBinder();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bind_service_btn:
Intent bindServiceIntent = new Intent(this, MyService.class);
bindService(bindServiceIntent,connection,BIND_AUTO_CREATE);
break;
case R.id.unbind_service_btn:
unbindService(connection);
break;
}
}
}
主要做了两件事:
- 创建ServiceConnection类,里面重写了onServiceConnected()方法和 onServiceDisconnected()方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用。
- 绑定服务和取消绑定服务,分别使用bindService方法和unbindService方法。
点击绑定服务按钮和取消绑定服务按钮,打印log如下
当程序调用unbindService()方法解除对某个Service的绑定时,系统会先回调该Service的 onUnbind()方法,然后再回调 onDestroy()方法。与多次调用startService()方法启动 Service 不同的是,多次调用 bindService()方法并不会执行重复绑定。对于前一个示例程序,用户每单击“启动Service”按钮一次,系统就会回调Service的onStartCommand()方法一次;对于这个示例程序,不管用户单击“绑定Service”按钮多少次,系统只会回调 Service 的onBind()方法一次。
Service声明周期
正常的启动Service和绑定Service的声明周期如下
如果应用程序通过startService()方法来启动Service, Service的生命周期如图左边所示。
如果应用程序通过bindService()方法来启动Service, Service的生命周期如图右边所示。
Service生命周期还有一种特殊的情形——如果Service已由某个客户端通过startService()方法启动了,接下来其他客户端调用bindService)方法绑定该Service后,再调用unbindService()方法解除绑定,最后又调用bindService()方法再次绑定到Service,这个过程所触发的生命周期方法如下。onCreate()→onStartCommand()→onBind()→onUnbind()(重写方法返回了true)→onRebind()
并没有发现Service回调onDestroy(方法,这是因为该Service并不是由Activity通过 bindService()方法启动的(该Service 事先已由Activity通过 startService()方法启动了),因此当Activity调用unBindService()方法取消与该Service的绑定时,该Service也不会终止。
由此可见,当Activity调用bindService()绑定一个已启动的Service时,系统只是把Service内部IBinder对象传给Activity,并不会把该Service生命周期完全“绑定”到该Activity, 因而当Activity调用unBindService()方法取消与该Service的绑定时,也只是切断该Activity 与Service之间的关联,并不能停止该Service组件。
参考:疯狂Android讲义