您的位置:首页 > 移动开发 > Android开发

Android bind service讲解以及跨进程通信

2016-04-26 19:05 585 查看
**

Android bind service讲解以及Messenger跨进程通信

**

android service是运行在后台的程序,说白了,就是没有界面,这里我想强调的一点是,运行在后台不等于运行在非主线程,除了IntentService外,普通的service如果你没有开启新的线程,那么默认是运行在主线程中的。

service有两种启动方式,一个是bind,一个是start,两种启动方式,有挺多区别。需要注意的是,bind绑定service的时候,直到最后一个bind到service的程序调用unbind,否则service一直会运行。而对于startservice这种启动方式来说,一旦启动,需要自己stopService或者调用service内部的stopSelf,否则该service是不会关闭的。

还需要注意的是service的声明周期,这个附张图就全明白了。



需要注意的是,onCreate方法只在你启动service的时候调用一次,之后再启动service的时候就直接走到onStartCommand()或者onBind()里了。

好了,废话不多说了,上个demo吧:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private boolean hasBound;
private Button intent_Service;
private Button start_Service;
private Button bind_Service;
private Button messenger_Service;
//下面的handler和Messenger使用来进行跨进程通信的
private Handler handler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==322)
{
Toast.makeText(getApplicationContext(),"receive message from server",Toast.LENGTH_SHORT).show();
}
}
};

private Messenger clientMessenger=new Messenger(handler);
private Messenger serverMessenger;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}

private void initView()
{
intent_Service= (Button) findViewById(R.id.intent_service);
intent_Service.setOnClickListener(this);
start_Service= (Button) findViewById(R.id.start_service);
start_Service.setOnClickListener(this);
bind_Service=(Button)findViewById(R.id.bind_service);
bind_Service.setOnClickListener(this);
messenger_Service=(Button)findViewById(R.id.messenger_service);
messenger_Service.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.intent_service:
//启动IntentService
Intent intentService=new Intent(this,IntentTestService.class);
startService(intentService);
break;
case R.id.start_service:
//start调用普通Sservice
Intent startService=new Intent(this,NormalService.class);
startService(startService);
break;
case R.id.bind_service:
//bind调用service
Intent bindService=new Intent(this,NormalService.class);
if(bindService.resolveActivity(getPackageManager())!=null)
bindService(bindService,connection,BIND_AUTO_CREATE);
break;
//利用Messenger进行跨进程通信
case R.id.messenger_service:
if(!hasBound) {
Intent intent = new Intent("com.skateboard.serverservice.service.BIND");
intent.setPackage("com.skateboard.serverservice");
bindService(intent, messengerConnection, Context.BIND_AUTO_CREATE);
}
else
{
sendMessageToServier();
}
break;
}
}

private ServiceConnection messengerConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
hasBound=true;
serverMessenger=new Messenger(service);
Message message=new Message();
message.what=233;
message.replyTo=clientMessenger;
try {
serverMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
hasBound=false;
}
};

private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
NormalService.NormalBinder binder= (NormalService.NormalBinder) service;
binder.bindMethod();
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};

private void sendMessageToServier()
{
Message message=new Message();
message.what=233;
message.replyTo=clientMessenger;
try {
serverMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
}
}


IntentTestService继承子IntentService,它的功能很简单,就是打印一行话 “intent service start”。比较特别的就是就如如上所说的,这个service是运行在非主线程的。

public class IntentTestService extends IntentService {

public IntentTestService()
{
super("IntentTestService");
}

/**
* Creates an IntentService.  Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentTestService(String name) {
super(name);
}

@Override
protected void onHandleIntent(Intent intent) {
System.out.println("intent service start");
}
}


NormalService可以接受startService()的方式启动同时也可以接受bindService的方式启动,这里主要讲讲bindService的启动方式,当我们bind到一个service的时候,回调用的onBind方法,这时会返回一个IBinder类,这个类个人觉得很想代理模式,通过它来调用service中的方法,在我们bindservice的时候,需要传入一个参数,ServiceConnection,在这个对象里面有两个回调方法,一个是ublic void onServiceConnected(ComponentName name, IBinder service)一个是public void onServiceDisconnected(ComponentName name),在onServiceConnected中的参数service就是我们在onBind方法中返回的IBinder,通过对它的转型,我们就可以调用相应的service中的方法了。所以这里我写了一个内部类NormalBinder,用它来打印“”bind method”并在onBind方法中返回他,这样我在MainActivity中就可以得到这个NormalBinder,并调用它内部的方法。

public class NormalService extends Service {
public NormalService() {
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("service start");
stopSelf();
return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
NormalBinder normalBinder=new NormalBinder();
return normalBinder;

}

@Override
public void onDestroy() {
super.onDestroy();
System.out.println("stop service");
}

public class NormalBinder extends Binder
{
public void bindMethod()
{
System.out.println("bind method");
}
}

}


对于这个流程,我本想画个示意图,但是太懒了,我决定还是文字吧。

跨进程通讯的方式有两种,一种是AIDL,一种就是利用Messenger了,这两种方式的区别就在鱼AIDL是多线程的,而Messenger是单线程的,也就是说利用Messenger的跨进程通信在消息队列中每次只有一个请求。需要注意的是如果你需要服务器回传数据给客户端,你需要在handler的public void handleMessage(Message msg)方法中得到客户端的Messenger,这个messenger就是Messenger clientMessenger=msg.replyTo;这是在客户端在向服务端发送Message的时候传递给message的参数。

public class ServerService extends Service {

private Handler handler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==233)
{
Messenger clientMessenger=msg.replyTo;
Message message=new Message();
message.what=322;
try {
clientMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
};

private Messenger messenger=new Messenger(handler);

public ServerService()
{

}

@Override
public void onCreate() {
super.onCreate();
System.out.println("service create");
}

@Override
public IBinder onBind(Intent intent) {
System.out.println("bind service");
return messenger.getBinder();
}
}


接着MainAcitivyt发起bindService的请求,(这里要注意的是,5.0以后,开启service的Intent必需是显示的Intent,所以你的Intent里必须要包含另一个程序的包名的信息。)在ServiceConnection中的onServiceConnected的方法里,通过返回的IBinder来得到相应的Messenger

private ServiceConnection messengerConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
hasBound=true;
serverMessenger=new Messenger(service);
Message message=new Message();
message.what=233;
message.replyTo=clientMessenger;
try {
serverMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
hasBound=false;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android messenger service