概述
Service启动方式分两种,一种启动服务startService()的方式,一种绑定服务bindService()*的方式。
启动 Service 并传递数据
通过startService()来启动一个Service服务,以这种方式启动的服务,Service会一直无限期运行下去,只有外部调用了stopService()方法时,该Service才会停止运行并销毁。
startService()和startActivity()类似,传入一个Intent对象,使用Intent对象来进行数据的传递。
Intent i = new Intent(this, MyService.class);
i.putExtra("data", "测试数据");
startService(i);
Service接收数据需要实现onStartCommand(Intent, int, int)方法,第一个参数Intent就是传递过来的Intent对象,使用getStringExtra()的方法获取传递过来的数据。
String data = intent.getStringExtra("data");
Log.d(TAG, "onStartCommand: 传递过来的数据: " + data);
绑定 Service 进行通信
bindService启动服务特点:
- bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
- client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService()方法启动中是无法实现的。
- bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁。
bindService绑定服务是需要传入三个参数Intent、ServiceConnection、int,其中Intent就是普通的Intent对象,与startService()传入的Intent对象一样,这个就不多说了;第三个参数是一个int类型的flag标志,固定传值Context.BIND_AUTO_CREATE。
重点说一下第二个参数ServiceConnection,传递数据通信也是在这个参数中实现的。ServiceConnection需要重写onServiceConnected和onServiceDisconnected两个方法,先说后者,Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了,但是当客户端解除绑定时,这个方法不会被调用;前者参数中的IBinder参数就是Service中onBind()方法返回的IBinder对象,运用Ibinder对象,就可以实现组件和Service之间的数据通信了。
private MyService.MyBinder mBindService;
//MyConn实现ServiceConnection与Service创建连接
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service是返回的IBinder类型的参数,需要使用MyBinder类型进行转换,MyBinder为MyBindService中的匿名内部类
mBindService = (MyService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
// service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了
// 当客户端解除绑定时,这个方法不会被调用.
}
}
上述代码中的MyService.MyBinder对象是MyService中创建的匿名内部类,也就是onBind()方法return的IBinder对象。
MyBinder类中定义一个setData()方法,用于获取组件Activity设置的数据。
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MyBinder();
}
public class MyBinder extends Binder{
public void setData(String data){
mData = data;
}
}
那么,绑定Service是如何绑定的呢?传递数据又是具体如何传递呢?
绑定Service使用bindService()来进行绑定,使用unbindService()进行解绑操作,传递数据时只需要使用上述代码中返回的MyBinder对象mBindService,来调用setData()方法即可,注意调用之前先进行非空判断。
case R.id.button3:
// 绑定Service
mConn = new MyConn();
bindService(new Intent(this, MyService.class), mConn, Context.BIND_AUTO_CREATE);
break;
case R.id.button4:
// 解绑Service
unbindService(mConn);
break;
case R.id.button5:
// bindService传递数据
if (mBindService != null){
mBindService.setData("bindService传递的测试数据");
}
break;
最后,附上整体代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyConn mConn;
private MyService.MyBinder mBindService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
findViewById(R.id.button3).setOnClickListener(this);
findViewById(R.id.button4).setOnClickListener(this);
findViewById(R.id.button5).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
// 启动Service
Intent i = new Intent(this, MyService.class);
i.putExtra("data", "测试数据");
startService(i);
break;
case R.id.button2:
// 停止Service
stopService(new Intent(this, MyService.class));
break;
case R.id.button3:
// 绑定Service
mConn = new MyConn();
bindService(new Intent(this, MyService.class), mConn, Context.BIND_AUTO_CREATE);
break;
case R.id.button4:
// 解绑Service
unbindService(mConn);
break;
case R.id.button5:
// bindService传递数据
if (mBindService != null){
mBindService.setData("bindService传递的测试数据");
}
break;
}
}
//MyConn实现ServiceConnection与Service创建连接
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service是返回的IBinder类型的参数,需要使用MyBinder类型进行转换,MyBinder为MyBindService中的匿名内部类
mBindService = (MyService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
// service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了
// 当客户端解除绑定时,这个方法不会被调用.
}
}
}
Service代码:
public class MyService extends Service {
private static final String TAG = "MyService";
private String mData = "默认数据";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MyBinder();
}
public class MyBinder extends Binder{
public void setData(String data){
mData = data;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mData = intent.getStringExtra("data");
Log.d(TAG, "onStartCommand: 传递过来的数据: " + mData);
new Thread(){
@Override
public void run() {
super.run();
while (true){
Log.d(TAG, "run: " + mData);
}
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}