Service
什么是Service
在后台长期运行的没有界面的组件。其他组件可以启动Service让他在后台运行,或者绑定Service与它进行交互,甚至实现进程间通信(IPC)。例如,可以让服务在后台处理网络交互,播放音乐,文件I/O,或者与ContentProvider交互。
创建一个Service
新建一个类,继承Service,重写相关方法,如onBind,onUnBind,onCreate,onDestorey。
在AndroidManifest.xml中配置Service和相关权限。
<manifest ... >
...
<application ... >
<service android:name=".MyService" />
...
</application>
</manifest>
开启服务:
Intent service = new Intent(this,Service.class);
startService(service);
停止服务:
Intent service = new Intent(this,Service.class);
stopService(service);
绑定服务:
private boolean mIsBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
// 服务连接成功回调
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder binder = (MyService.MyBinder) service;
}
// 服务失去连接回调
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Event(value = R.id.btn_bind_service)
private void onBindServiceClick(View view) {
bindService(getServiceIntent(), mConnection, Context.BIND_AUTO_CREATE);// 绑定时如果没有创建Service则自动创建Service。
mIsBound = true;
}
解绑服务:
@Event(value = R.id.btn_unbind_service)
private void onUnbindServiceClick(View view) {
if (!mIsBound) {
ToastUtil.show("未绑定服务");
return;
}
try {
unbindService(mConnection);//注意:ServiceConnection要传绑定时的ServiceConnection对象,否则会报错。
} catch (Exception e) {
ToastUtil.show("解除綁定服务失败");
e.printStackTrace();
}
mIsBound = false;
}
Service的生命周期
public class MyService extends Service {
// 服务创建
@Override
public void onCreate() {
super.onCreate();
}
// 每次startService都会调用;通过bindService方式启动服务,该方法不会被调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
// 服务销毁
@Override
public void onDestroy() {
super.onDestroy();
}
// bindService时调用,返回一个IBinder对象,用于与Service交互,IBinder就是Service的代理
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
// unbindService时调用
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
startService:onCreate——>onStartCommand
stopService:onDestory
注意:服务只会被创建一次,如果服务已经创建,并且没有销毁,多次调用startService方法,只会执行onStartCommand方法。
bindService:onCreate——>onBind
unbindService:onUnbind——>onDestory
注意:
如果多次bindService,onBind方法只会在第一次绑定时被调用;同样,多次startService,onCreate方法也只会在第一次创建时被调用;
服务只能被解绑一次,服务需要先绑定才能解除绑定,多次解绑会报错。
通过bindService方式启动的Service,在调用unbindService时就会自动销毁。
服务只会停止一次,多次调用stopService()的方法无效,但不报错。
每次调用startService()开启服务都会执行onStartCommand()方法。
如何调用Service里的方法
由于系统框架在创建服务的时候会创建与之对应的上下文,直接new出来的服务对象是没有上下文的,所以直接new服务对象调用其方法会报异常。
与Service之间交互都是通过其代理人(IBinder)来间接调用Service里的方法的。
这样设计主要出于安全考虑,有限的暴露出一些方法,而不是直接返回服务对象,因为服务对象里可能有一些成员变量和方法不允许外界直接访问,需要保护起来。
一般IBinder(代理人)也应该设计成私有的,因为是IBinder中的一些数据也需要保护起来,只需要暴露出一些指定的方法,那么外界如何引用IBinder对象呢?通过接口引用代理人,在接口定义供外界调用的方法,让IBinder类实现该接口。
bindService与startService
bindService与startService的区别:
绑定服务:可以间接调用服务里面的方法;如果绑定的Activity被销毁了,服务也会跟着销毁。
开启服务:不可以调用服务里面的方法;如果开启服务的Activity销毁,服务还可以长期的在后台运行。
既要保证服务长期在后台运行,又想去调用服务里面的方法:
步骤:
1. startService(),保证服务在后台长期的运行;
2. bindService(),获取中间人(IBinder对象),间接的调用服务里面的方法;
这时,解绑服务并不会导致服务销毁,服务可长期在后台运行。
注意:如果服务已经被绑定,直接调用stopService()是停不掉的,必须先解除绑定服务再调stopService(),服务才会被销毁。
示例代码
@ContentView(value = R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
private boolean mIsBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
// 服务连接成功回调
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtil.d(name + " onServiceConnected");
PayService.PayBinder binder = (PayService.PayBinder) service;
binder.pay(100);
}
// 服务失去连接回调
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtil.d(name + " onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//当Activity被销毁时解绑服务,因为如果已经绑定服务不显式解绑会报异常。
onUnbindServiceClick(null);
}
private Intent getServiceIntent() {
return new Intent(this, PayService.class);
}
// 启动服务
@Event(value = R.id.btn_start_service)
private void onStartServiceClick(View view) {
startService(getServiceIntent());
}
// 绑定服务
@Event(value = R.id.btn_bind_service)
private void onBindServiceClick(View view) {
bindService(getServiceIntent(), mConnection, Context.BIND_AUTO_CREATE);// 绑定时如果没有创建服务则自动创建Service。
mIsBound = true;
}
// 解绑服务
@Event(value = R.id.btn_unbind_service)
private void onUnbindServiceClick(View view) {
if (!mIsBound) {
ToastUtil.show("未绑定服务");
return;
}
try {
unbindService(mConnection);//注意:ServiceConnection要传绑定时的ServiceConnection对象,否则会报错。
} catch (Exception e) {
e.printStackTrace();
}
mIsBound = false;
}
// 停止服务
@Event(value = R.id.btn_stop_service)
private void onStopServiceClick(View view) {
stopService(getServiceIntent());
}
}