Android Service
image.png
创建、配置 Service
- 定义一个继承
Service的子类
public class TestService extends Service {
/*
Service 被绑定时回调该方法
必须实现的方法,返回一个 IBinder 对象,应用程序可通过该对象与 Service 组件通信
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println("intent = " + intent);
return null;
}
/*
Service 被创建时回调该方法
*/
@Override
public void onCreate() {
super.onCreate();
System.out.println("onCreate");
}
/*
Service 被启动时回调该方法
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
/*
Service 被关闭之前回调该方法
*/
@Override
public void onDestroy() {
super.onDestroy();
}
/*
当该 Service 上绑定的所有客户端都断开连接时将会回调该方法
*/
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
- 在
AndroidManifest.xml文件中配置该Service
<service
android:name=".TestService"
android:enabled="true"
android:exported="true"></service>
-
name指定该Service的实现类类名 -
exported指定该Service是否能被其它 APP 启动。如果在配置该Service时指定了<intent-filter.../>子元素,则该属性默认为true -
permission指定启动该Service所需的权限 -
process指定该Service所处的线程,该Service组件默认处于该 APP 所在的进程中。Android 四大组件都可通过该属性指定进程
没有配置 <intent-filter.../> 意味着该 Service 不能响应任何 Intent,只能通过指定 Component 的 Intent 来启动
运行 Service 的两种方式
- 通过
Context的startService()方法:通过该方法启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行。 - 通过
Context的bindService()方法:使用该方法启动Service,访问者与Service绑定在一起,访问者一旦退出,Service也就终止了。
启动和停止 Service
// 创建启动Service的Intent
Intent intent = new Intent(this, TestService.class);
// 启动指定Service
startBn.setOnClickListener(view -> this.startService(intent));
// 停止指定Service
stopBn.setOnClickListener(view -> stopService(intent));
绑定本地 Service 并与之通信
当程序通过 stariService() 和 StopService() 启动、关闭 Service 时,Service 与访问者之间基本上不存在太多的关联,因此 Service 和访问者之间也无法进行通信、交换数据。
如果 Service 和访问者之间需要进行方法调用或交换数据,则应该使用 bindService() 和 unbindService() 方法启动、关闭 Service。
-
service该参数通过Intent指定要启动的Service。 -
conn该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)方法;当Service所在的宿主进程由于异常中止或其他原因终止,导致该Service与访问者之间断开连接时回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。当调用者主动通过unbindService()方法断开与Service的连接时,ServiceConnection时象的onServiceDisconnected(ComponentName name)方法并不会被调用。 -
flags指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为 0(不自动创建)或 BIND_AUTO_CREATE(自动创建)。
BindService
public class BindService extends Service {
private int count;
private boolean quit;
// 定义onBinder方法所返回的对象
private MyBinder binder = new MyBinder();
// 通过继承Binder来实现IBinder类
class MyBinder extends Binder // ①
{
// 获取Service的运行状态:count
public int getCount() {
return BindService.this.count;
}
}
// Service被绑定时回调该方法
@Override
public IBinder onBind(Intent intent) {
System.out.println("Service is Binded");
// 返回IBinder对象
return binder;
}
// Service被创建时回调该方法
@Override
public void onCreate() {
super.onCreate();
System.out.println("Service is Created");
// 启动一条线程,动态地修改count状态值
new Thread(() ->
{
while (!quit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
BindService.this.count++;
}
}).start();
}
// Service被断开连接时回调该方法
@Override
public boolean onUnbind(Intent intent) {
System.out.println("Service is Unbinded");
return true;
}
// Service被关闭之前回调该方法
@Override
public void onDestroy() {
super.onDestroy();
this.quit = true;
System.out.println("Service is Destroyed");
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
// 保持所启动的Service的IBinder对象
private BindService.MyBinder binder;
// 定义一个ServiceConnection对象
private ServiceConnection conn = new ServiceConnection() {
// 当该Activity与Service连接成功时回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("--Service Connected--");
// 获取Service的onBind方法所返回的MyBinder对象
binder = (BindService.MyBinder) service; // ①
}
// 当该Activity与Service断开连接时回调该方法
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("--Service Disconnected--");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取程序界面中的start、stop、getServiceStatus按钮
Button bindBn = findViewById(R.id.bind);
Button unbindBn = findViewById(R.id.unbind);
Button getServiceStatusBn = findViewById(R.id.getServiceStatus);
// 创建启动Service的Intent
Intent intent = new Intent(this, BindService.class);
bindBn.setOnClickListener(view ->
// 绑定指定Service
bindService(intent, conn, Service.BIND_AUTO_CREATE));
unbindBn.setOnClickListener(view ->
// 解除绑定Service
unbindService(conn));
getServiceStatusBn.setOnClickListener(view ->
// 获取并显示Service的count值
Toast.makeText(MainActivity.this, "Service的count值为:" +
binder.getCount(), Toast.LENGTH_SHORT).show()); // ②
}
}
IntentService
IntentService 是 Service 的子类
Service存在的两个问题
-
Service不会专门启动一个单独的进程,Service与它所在应用位于同一个进程中。 -
Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务。
IntentService 将会使用队列来管理请求 Intent,每当客户端代码通过 Intent 请求启动 IntentService 时,IntentService 会将该 Intent 加入队列中,然后开启一条新的 worker 线程来处理该 Intent。对于异步的 startService() 请求,IntentService 会按次序依次处理队列中的 Intent,该线程保证同一时刻只处理一个 Intent。由于 IntentService 使用新的 worker 线程处理 Intent 请求,因此 IntentService 不会阻塞主线程,所以 IntentService 自己就可以处理耗时任务。
IntentService 具有如下特征
-
IntentService会创建单独的worker线程来处理所有的Intent请求。 -
IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无须处理多线程问题。 - 当所有请求处理完成后,
IntentService会自动停止,因此开发者无须调用stopSelf()方法来停止该Service。 - 为
Service的onBind()方法提供了默认实现,默认实现的onBind()方法返回null。 - 为
Service的onStartCommand()方法提供了默认实现,该实现会将请求Intent添加到队列中。
TestIntentService
不会阻塞前台 UI 线程,可顺利完成任务
public class TestIntentService extends IntentService {
public TestIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 该方法内可以执行任何耗时任务,比如下载文件等,此处只是让线程暂停20秒
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStartCommand");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("---耗时任务执行完成---");
}
}
TestService
会导致程序 UI 线程被阻塞,阻塞时间过长会出现 ANR 异常
public class TestService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 该方法内执行耗时任务可能导致ANR(Application Not Responding)异常
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStart");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("---耗时任务执行完成---");
return START_STICKY;
}
}
public void startService(View source) {
// 创建需要启动的Service的Intent
Intent intent = new Intent(this, TestService.class);
// 启动Service
startService(intent);
}
public void startIntentService(View source) {
// 创建需要启动的IntentService的Intent
Intent intent = new Intent(this, TestIntentService.class);
// 启动IntentService
startService(intent);
}
摘抄至《疯狂Android讲义(第4版)》