Android的Service提供给我们强大的后台处理能力,并可以用其进行IPC,鄙人看了看官方文档,总结了下文档提到的三种绑定Service的方式,并根据提供的样例整合写了自己的一个demo,来试试自己对基本使用的掌握。
1、bindlocal按钮式绑定一个本地服务,即在同一进程、同一个app内的Service,calculate按钮调用绑定的本地服务,把最上面两个edittext的用户输入数字得到做计算;
2、bindremote(Messenger)按钮绑定一个远程服务(即不在同一个进程内),但是是线程不安全的,所有的调用都是以消息队列形式发出,who R U是绑定后调用这个远程服务;
3、bindremote(AIDL)按钮是用aid机制l绑定一个远程服务,这样是线程安全的,绑定完成后立即调用了该服务的两个方法;
这样看来,这个demo就有两个工程,一个包括三种服务的客户端及本地服务,另一个包括两个远程服务(没有界面);
对了,这里我嫌每次写Toast麻烦,定义了
public void T(String txt) {
Toast.makeText(this, txt, Toast.LENGTH_SHORT).show();
}
下面先看第一组功能——本地服务:
服务的源码如下,注意千万不要忘了在Manifest中声明
public class CalcService extends Service {
private final IBinder calcBinder=new CalcBinder();
public class CalcBinder extends Binder{
public CalcService getService(){
return CalcService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return calcBinder;
}
public int sum(int a,int b){
return a+b;
}
}
在Activity中绑定的方法如下:
public void bindLocal(View v) {
Intent bind = new Intent(this, CalcService.class);
connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
T("local binder disconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
T("local binder connected");
localServie = ((CalcBinder) service).getService();
}
};
bindService(bind, connection, Context.BIND_AUTO_CREATE);
}
public void calc(View v) {
try {
int a = Integer.parseInt(et1.getText().toString());
int b = Integer.parseInt(et2.getText().toString());
T("result:" + localServie.sum(a, b));
} catch (NumberFormatException e) {
T("illegal format");
e.printStackTrace();
}
}
public void unbind(View v) {
if (connection != null)
unbindService(connection);
}
也就是说要重建一个新的Android工程,写个Service,代码如下:
package com.lttclaw.servicedemo2;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.widget.Toast;
public class RemoteServiceCalc extends Service {
@Override
public IBinder onBind(Intent intent) {
return new Messenger(new IncomingHandler()).getBinder();
}
class IncomingHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
Toast.makeText(getApplicationContext(), "I am far away ", Toast.LENGTH_LONG).show();
break;
default:
break;
}
super.handleMessage(msg);
}
}
}
别忘了加Manifest里哦!
public void bindMessenger(View v) {
Intent messengerbinder = new Intent();
messengerbinder.setComponent(new ComponentName(
"com.lttclaw.servicedemo2",
"com.lttclaw.servicedemo2.RemoteServiceCalc"));
connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
T("messenger binder disconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
T("messenger binder connected");
messenger = new Messenger(service);
}
};
bindService(messengerbinder, connection, Context.BIND_AUTO_CREATE);
}
调用服务的方法是这样的
public void who(View v) {
if (messenger == null)
return;
Message msg = Message.obtain();
msg.what = 0;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
最重要的一点是要写一个.aidl的文件,并且这个文件在客户端和服务端(在我这儿就是demo1和demo2中放在同一个路径下),我贴个图说明
好了,先写服务端,即demo2的aidl文件,这里aidl有些类型规范什么的想了解的可以查资料,我就不说详细的了(其实我不会……)写了个很简单的接口文件,长这个样子
package com.lttclaw.aidl;
interface RemoteAIDL{
int factorial(int a);
void introduce();
}
写好后编译器会在gen下面生成一个对应的java文件,有兴趣可以看看,反正我是看得一头雾水~_~ 然后我们来写一下这个接口的实现,这里真名叫RemoteAIDLImpl其实是个Service,代码如下:
package com.lttclaw.aidl;
import com.lttclaw.aidl.RemoteAIDL.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Toast;
public class RomoteAIDLImpl extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final RemoteAIDL.Stub mBinder=new Stub() {
@Override
public void introduce() throws RemoteException {
Toast.makeText(getApplicationContext(), "aidl", Toast.LENGTH_LONG).show();
}
@Override
public int factorial(int a) throws RemoteException {
if(a<1) return 0;
int result;
for(result=1;a>1;a--)
result*=a;
return result;
}
};
}
主要就是实现那个aidl的stub并将一个实例丢给onBind返回值。记得Manifest哟!
这里我不胜其烦,为其加上了action,以方便跨进程调用
好啦,再回到客户端,也就是demo1中,先把刚才的.aidl文件复制到一个一样的包路径下,见示例图,然后就会在gen下面也生成一个对应的java文件了,然后我们看绑定服务 的方法:
public void bindAIDL(View v) {
Intent bindaidl=new Intent();
bindaidl.setAction("com.lttclaw.aidl");
connection=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
T("aidl bind");
RemoteAIDL serviceAidl=RemoteAIDL.Stub.asInterface(service);
try {
T("result:"+serviceAidl.factorial(8));
serviceAidl.introduce();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
bindService(bindaidl, connection, Context.BIND_AUTO_CREATE);
}