服务(Service)是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互并且还要求长期运行的任务。Service不依赖于任何界面。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。
服务的基本用法
1.定义一个服务
创建一个service,我们新建一个MyService集成Service,并重写onCreate()
、onStartCommand()
、和onDestroy()
方法。
public class MyService extends Service{
private static final String TAG = "MyService";
@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() {
// 服务销毁时调用
super.onDestroy();
Log.d(TAG, "onDestroy: 服务销毁");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
如同四大组件中其他组件,每一个服务都需要在 AndroidManifest.xml 文件中注册才能生效。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
<service
android:name=".service.MyService"/>
</application>
如此我们便定义好一个服务,接下来需要做的就是启动这个服务
2.启动和停止服务
Service 的启动和停止主要是借助 Intent 来实现的,我们在项目中生成一个界面来控制服务的启动和停止。
在Activity中,对两个按钮添加点击事件,以便触发服务的启动和停止。
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
break;
}
}
点击 START_SERVICE 按钮后,logcat日志如下
我们可以看到,第一次启动服务时,onCreate()
方法和onStartCommand()
方法分别执行一次,如果我们此时再次点击 START_SERVICE 按钮,logcat 日志如下
我们可以看到,无论我们点击几次START_SERVICE按钮,onCreatef()
只会在服务第一次创建的时候调用,而onStartCommand()
方法则在每次启动服务的时候都会调用。
当我们点击 STOP_SERVICE 后,日志打印如下
服务调用onDestroy()方法,被销毁了。
除了在活动中调用 stopService()
方法停止服务外,在 MyService 中任意一个位置调用stopSelf()
方法都可以让服务停下来。
服务和活动之间通信
上面的代码中,我们在 Activity 中启动了 Service,然后服务处于一直运行的状态。可之后,Service 和 Activiy 之间就没有任何联系了。为了Acticity可以对Service进行有效的控制,需要绑定服务。
我们修改MyService类中的代码,新建内部类 MyBinder,在 MyBinder 中写一个打印信息的方法 ShowInfo()
,并让MyService中 onBind()
方法返回 MyBinder 的实例。
public class MyService extends Service {
private MyBinder mBinder = new MyBinder();
...
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class MyBinder extends Binder {
public void ShowInfo() {
Log.d(TAG, "ShowInfo: 执行ShowInfo方法");
}
}
}
我们在之前的界面上新增两个 Button ,分别用于绑定服务和取消服务。
修改 Activity 代码如下
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private Button start_service;
private Button stop_service;
private Button bind_service;
private Button unbind_service;
private MyService.MyBinder mBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: 服务绑定");
mBinder = (MyService.MyBinder) service;
mBinder.ShowInfo();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
start_service = (Button) findViewById(R.id.start_service);
stop_service = (Button) findViewById(R.id.stop_service);
bind_service = (Button) findViewById(R.id.bind_service);
unbind_service = (Button) findViewById(R.id.unbind_service);
start_service.setOnClickListener(this);
stop_service.setOnClickListener(this);
bind_service.setOnClickListener(this);
unbind_service.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);// 绑定服务
// BIND_AUTO_CREATE 表示服务绑定后自动创建服务。会执行service的onCreate()方法,但onStartCommand()不会执行
break;
case R.id.unbind_service:
unbindService(connection); // 解绑服务
break;
}
}
}
首先,我们创建了一个 ServiceConnection 的内部类,重写它的 onServiceConnected()
方法和onServiceDisconnected()
方法,这两个方法分别会在服务绑定成功和服务解绑后调用。
在onServiceConnected()
方法中,通过向下转型获取 MyBinder 实例,然后就可以调用 MyBinder 中任何 Public 方法了。
在 BIND_SERVICE 的点击事件中,通过bindService()
实现服务于活动的绑定。点击按钮后logcat如下
我们在
bindService()
中设置了 BIND_AUTO_CREATE 标志位,该标志表示服务绑定后自动创建服务。会执行service的onCreate()
方法,但onStartCommand()
不会执行
点击 UNBIND_SERVICE 后,打印日志如下
服务的生命周期
调用 startService()
方法后,再次调用stopService()
方法,onDestroy()
就会执行;
调用bindService()
方法后,再次调用unBindService()
方法,onDestroy()
就会执行;
如果既调用了startService()
方法,又调用了bindService()
方法,则必须同时调用stopService()
和unBindService()
方法,onDestroy()
才会执行;
使用IntentService
服务中的代码默认都是执行在主线程中的。如果在服务中处理耗时操作,很容易出现ANR(Application Not Responding)。
为了防止ANR的发生,我们应该在每个具体的方法里开启一个子线程,然后在这里执行耗时操作。这种服务一旦启动,就会一直处于运行状态,必须调用stopService()
或 stopSelf()
方法才能停下来。代码如下
public class MyService extends Service {
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 服务启动时调用
Log.d(TAG, "onStartCommand: 服务启动");
new Thread(new Runnable() {
@Override
public void run() {
// TODO: 执行耗时操作
// 在适当的时候结束服务
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
为了处理这种耗时操作,Android提供了一个 IntentService 类,集开启线程和自动停止于一身。
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: 服务启动");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: 服务销毁");
}
}
我们在 Activty 中新建 Button,并设置点击事件启动 IntentService。
case R.id.intent_service:
Intent intentServiceIntent = new Intent(this, MyIntentService.class);
startService(intentServiceIntent); // 启动服务
break;
打印日志如下,服务在执行完毕后自动停止了。
写在最后
学疏才浅,写作仓促,如果纰漏之处还望指正,不胜感激。