Android 四大组件——服务 后台运行解决方案

时间:2022-12-09 17:23:51

转载请注明出处:http://blog.csdn.net/smartbetter/article/details/51488281

Android 四大组件已经说了三个了,还差最后一个,服务(Service)。服务是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互还要长期运行的任务。需要注意的是,服务并不是运行在一个独立的进程中的,而是依赖于创建服务时所在的应用程序进程,当应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。另外需要注意的是,服务中的代码都是默认运行在主线程中的,如果直接在服务里去处理一些耗时的操作,就很容易出现ANR的情况,所以正确的做法是在每个服务的每个具体方法中开启一个子线程,然后在这里去处理那些耗时操作。

1.创建一个服务

首先创建一个服务类,继承 Service类:

public class MyService extends Service {
// 必须实现,绑定该Service时被回调
@Override
public IBinder onBind(Intent intent) {
return null;
}
// 服务被创建时回调
@Override
public void onCreate() {
super.onCreate();
// 定义相关业务逻辑
}
// 每次服务启动时回调
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 开启子线程,定义相关业务逻辑
return START_STICKY;
}
// 服务销毁时回调
@Override
public void onDestroy() {
super.onDestroy();
// 回收资源
}
}

然后在 AndroidManifest.xml 中注册服务:

<service android:name=".MyService"
android:enabled="true"
android:exported="true">

</service>

接下来就可以运行Service了。

2.启动和停止服务

1.普通方式

启动和停止服务主要是借助 Intent 来实现的。

Intent startIntent = new Intent(context, MyService.class);
startService(intent); // 启动服务
// Intent stopIntent = new Intent(context, MyService.class);
// stopService(intent); // 停止服务

如果服务想在某种状态自己停止,也是可以的,只需要在 MyService 的任何一个位置 调用 stopSelf() 方法就能让这个服务停止下来了。

2.绑定方式 活动与服务进行通信

当程序使用startService()、stopService()启动、关闭服务时,服务与活动之间就无法进行通信、数据交换,所以下面介绍另一种方式启动和停止服务的方式,调用 Context 的 bindService() 来获取一个服务的持久连接,这时就会回调服务中的 onBind() 方法。

public class MyService extends Service {
private int count;
private MyBinder binder = new MyBinder();
class MyBinder extends Binder {
public int getCount() {
return count; // 获取Service的运行状态
}
}
// 必须实现,绑定该Service时被回调
@Override
public IBinder onBind(Intent intent) {
return binder;
}
// 服务被创建时回调
@Override
public void onCreate() {
super.onCreate();
// 定义相关业务逻辑
count = 100;
}
// 每次服务启动时回调
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 开启子线程,定义相关业务逻辑
return START_STICKY;
}
// 服务销毁时回调
@Override
public void onDestroy() {
super.onDestroy();
// 回收资源
}
}

接下来定义一个活动来绑定该服务,并在该活动中通过MyBinder对象访问Service的内部状态。对于服务的 onBind(Intent intent) 方法返回的 IBinder对象 来说,Service允许客户端通过该IBinder对象来访问Service内部的数据,这样即可实现客户端与Service之间的通信。

public class MainActivity extends AppCompatActivity {
private MyService.MyBinder binder;
private ServiceConnection connection = new ServiceConnection() {
// 当该活动与服务连接成功时回调
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 获取Service的onBind方法所返回的MyBinder对象
binder = (MyService.MyBinder) service;
Log.i("JAVA", "count:"+binder.getCount());
}
// 当该活动与服务断开连接时回调,主动调用unbindService()方法断开连接时不回调
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Intent bindIntent = new Intent(context, MyService.class);
// 参数1:指定要启动的服务
// 参数2:用于监听访问者与Service之间的连接情况
// 参数3:指定绑定时是否创建Service, 0:不自动创建; BIND_AUTO_CREATE:自动创建
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
// unbindService(connection); // 解绑服务
}
}

需要注意的是,如果一个服务既调用了 startService(),又调用了 bindService(),那么销毁服务的时候需要 同时调用 stopService() 和 unbindService()。

3.服务的生命周期

下面我们来看一下 服务的生命周期:

Android 四大组件——服务 后台运行解决方案

4.使用前台服务保持持续运行

如果你希望服务可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台服务。前台服务和后台服务最大的区别就在于它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏可以看到更加详细的信息,有点类似通知的效果。当然,还有一些项目是由于特殊需求而使用前台服务的,例如后台更新天气数据的同时,还会在系统状态栏一直显示当前的天气信息。

创建前台服务并不复杂,修改 MyService 中的代码为:

public class MyService extends Service {
...
// 服务被创建时回调
@Override
public void onCreate() {
super.onCreate();
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))
.build();
// 参数1:保证为每个通知所指定的id都是不同的; 参数2:Notification对象
startForeground(1, notification);
// 定义相关业务逻辑
count = 100;
}
...
}

可以看到,这里只是修改了onCreate() 的代码,这部分代码就是简单创建 通知 的代码,只不过构建 Notification 对象后并没有使用 NotificationManager 来将通知显示出来,而是调用了 startForeground() 方法,让 MyService 变成一个前台服务,并在系统状态栏显示出来。

Android 四大组件——服务 后台运行解决方案

5.使用IntentService轻松避免ANR

服务中的代码都是默认运行在主线程中的,如果直接在服务里去处理一些耗时的操作,就很容易出现ANR的情况,所以正确的做法是在每个服务的每个具体方法中开启一个子线程,然后在这里去处理那些耗时操作。但是,这种服务一旦启动之后,就会一直处于运行状态,必须调用 stopService() 或者 stopSelf() 方法才能让服务停止下来,为了简单创建一个异步的、会自动停止的服务,Android 为我们提供了 IntentService 类,这个类就很好的解决了前面的问题,下面看一下它的用法:

public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
// 在这个方法中处理一些具体的逻辑,这个方法已经在子线程中运行了,并且在服务运行结束后是会自动停止的。
@Override
protected void onHandleIntent(Intent intent) {
}
@Override
public void onDestroy() {
super.onDestroy();
}
}