Service(服务):运行与后台的一个组件,行适合运行在后台的代码,服务是没有前台界面,可以视为没有界面的activity。
一.服务的开启方式
startService:该方法启动的服务所在的进程属于服务进程,Activity一旦启动服务,服务就跟Activity没有任何关系。
bindService:该方法启动的服务所在进程不属于服务进程, Activity与服务建立连接,Activity一旦死亡,服务也会死亡
混合调用:先开始、再绑定,先解绑、再停止,生命周期方法:onCreate->onBind->onUnbind->onDestroy
二.服务与activity的通信
1.建立class 类继承Service类,并在清单文件中注册该服务,name与java文件所在的包名和java名字一致。
<service android:name="com.example.musicplayer.MusicService"></service>
2.在自己建立的service类中定义私有方法,这个方法在activity中是不能访问的,然而要实现通信就必须要访问该方法。
a)首先将service中的方法定义成一个接口。
b)在service中定义一个中间人类,继承Binder并实现上述的接口。
c)在public IBinder onBind(Intent intent)方法中返回中间人类的对象
public class MusicService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new MusicController();
}
//必须继承Binder才能作为中间人对象返回
class MusicController extends Binder implements MusicInterface{
public void play(){
MusicService.this.play();
}
public void pause(){
MusicService.this.pause();
}
}
public void play(){
System.out.println("play");
}
public void pause(){
System.out.println("pause");
}
}
3.在activity中开启服务,因为是activity与服务通信,所以必须绑定服务,当中值得注意的是bindService函数中的第二个参数,该参数我们需要在activity中新建一个类,该的类的对象作为参数,目的是拿到service中返回的中间人对象,然后访问其中的方法。
public class MainActivity extends Activity {
//定义一个接口对象接收service中返回的中间人
MusicInterface mInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,MusicService.class);
//混合调用,将服务所在进程变成服务进程
startService(intent);
bindService(intent, new MusicServiceConn(), BIND_AUTO_CREATE);
}
//该类主要目的是获取中间人对象
class MusicServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
//将中间人对象强制转换成接口对象
mInterface = (MusicInterface) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
//通过接口对象访问其中的方法
public void play(View v){
mInterface.play();
}
public void pause(View v){
mInterface.pause();
}
}
三.服务的分类
1.本地服务:指的是服务和启动服务的activity在同一个进程中
2.远程服务:指的是服务和启动服务的activity不在同一个进程中
四.AIDL实现远程服务,进程间的通信
1. 把远程服务的方法抽取成一个单独的接口java文件
2. 把接口java文件的后缀名改成aidl
3. 在自动生成的PublicBusiness.java文件中,有一个静态抽象类Stub,它已经继承了binder类,实现了publicBusiness接口,这个类就是新的中间人
4. 把aidl文件复制粘贴到启动远程服务项目,粘贴的时候注意,aidl文件所在的包名必须跟远程服务项目中aidl所在的包名一致,新建一个包存放该AIDL
5. 在远程服务项目中,强转中间人对象时,直接使用Stub.asInterface()
6. 启动远程服务端启动的服务名字必须远程服务端的action一模一样。详细代码如下:
远程服务端:
启动远程服务:
//远程服务端
public class PayService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new pay_sy();
}
//中间人对象
class pay_sy extends Stub{
@Override
public void pay_sy() throws RemoteException {
pay();
}
}
public void pay(){
System.out.println("支付成功");
}
}
//启动服务端
public class MainActivity extends Activity {
//接口对象
private PayInterface ps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
//设置需要启动服务的action
intent.setAction("com.lzz.sy");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ps = Stub.asInterface(service);
}
}, BIND_AUTO_CREATE);
}
public void click(View v){
try {
ps.pay_sy();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}