1当一个进程需要调用另外一个进程的方法时候,进程可以通过aidl文件以接口的方式将方法抛出。比如android没有对外提供挂电话的方法,若用户想要调用这个方法就必须与电话管理这个应用程序通信,调用挂电话的方法。
2、下面我就举例一个demo调用远程服务里的方法。为了验证service能否单独启动,这个demo启动了2个远程服务,一个有activity的一个只有service的。并且他们抛出的接口名字相同,正好学习一下同名的引用,发现一个java文件里只能import 1个同同名的类,若想调用另外一个同名类则只有引用他的全路径名:包名+类名。
(1)、含activity远程服务和接口:(注意:清单文件里需要配置service)
//服务
package com.example.androidservice;
import com.example.androidservice.Iservicemethod.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class IService extends Service {
@Override
public IBinder onBind(Intent intent) {
System.out.println("onbind");
return new Mybindle();
}
@Override
public void onCreate() {
System.out.println("oncreate");
super.onCreate();
}
private class Mybindle extends Stub
//一旦修改接口的扩展名为aidl,就会在gen文件下与接口所在包名同名,里面自动生成一个接口名的java文件,通过查看该接口,
发现里面自动实现了一个内部类Stub,它实现Ibundle和抛出的接
口public static abstract class Stub extends android.os.Binder implements com.example.demoonlyservice.Iservicemethod,
因此我们实现返回的Ibundle的时候写的类可以直接继承Stub即可,后面调用Stub里的方法可以返回接口,即将返回去的bundle service实例化接口,通过接口来调用服务里的方法。
{
@Override
public void sayhello() throws RemoteException {
// TODO Auto-generated method stub
// sayhello(); // (1)接口抛出的方法名字不能和服务的名字相同,否则覆写的时候不能调用,我先开始直接调用发现和覆写名相同出现 // 无限循环
// System.out.println("hello service!!!"); // (2)一旦在接口定义了该方法,生成了aidl文件后,就不能修改覆写方法里的内容,内里实现的方法是调用service里 // 的方法,因此可以修改service里的方法来修改接口抛出的方法。
sayhello2();
}
}
public void sayhello2()
{
System.out.println("hello service!!!");
System.out.println("hello service2!!!");
}
}
//抛出的接口
package com.example.androidservice;
interface Iservicemethod {
void sayhello();
}
第二个只含service的服务和接口:(注意:清单文件里也需要配置service)
package com.example.demoonlyservice;
import com.example.demoonlyservice.Iservicemethod.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class IService extends Service {
@Override
public IBinder onBind(Intent intent) {
System.out.println("onbind");
return new Mybindle();
}
@Override
public void onCreate() {
System.out.println("oncreate");
super.onCreate();
}
private class Mybindle extends Stub
{
@Override
public void sayhello() throws RemoteException {
// TODO Auto-generated method stub
// sayhello();
// System.out.println("hello service!!!");
sayhello2();
}
}
public void sayhello2()
{
System.out.println("hello service!!!");
}
}
//接口
package com.example.demoonlyservice;
interface Iservicemethod {
void sayhello();
}
3在这个应用里通过点击2个按钮调用上面的2个服务,通过返回的Ibundle实现了接口方法来调用服务的方法sayhello
package com.example.getothermehod;
import com.example.androidservice.Iservicemethod;
//import com.example.demoonlyservice.Iservicemethod;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends ActionBarActivity {
private Iservicemethod is;
private com.example.demoonlyservice.Iservicemethod is2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Intent intent=new Intent("onlyservice");
// bindService(intent, new Myconnect2(), BIND_AUTO_CREATE);
}
public void startonlyservice(View v) throws InterruptedException
{
Intent intent=new Intent("onlyservice");
bindService(intent, new Myconnect2(), BIND_AUTO_CREATE);
// try {
// is2.sayhello();
// } catch (RemoteException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// Thread.sleep(2000);
System.out.println(is2==null);
}
public void startservice(View v)
{
Intent intent=new Intent("providerservice");
bindService(intent, new Myconnect(), BIND_AUTO_CREATE);
// try {
// is.sayhello();
// } catch (RemoteException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
class Myconnect implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("fuck");
is=Iservicemethod.Stub.asInterface(service);
try {
is.sayhello();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
class Myconnect2 implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("fuck");
is2=com.example.demoonlyservice.Iservicemethod.Stub.asInterface(service);
try {
is2.sayhello();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
}
下面总结一下完成的步骤和注意的问题:
1 、首先创建一个远程服务,demo里创建了2个,并且服务的名字相同,在清单文件里注册的action不同而已。服务里有个方法需要被其他的应用程序访问,即sayhello。
2、定义一个接口,接口里有需要被调用的方法,名字不要与服务里需要的方法同名(具体说明见第一个服务里mybundle类实现的代码解释部分),去掉接口和方法前面的访问权限,即public,private等,并到相应文件目录下将接口扩展名修改为aidl,保存刷新项目,会发现在gen文件下的和接口同包名的目录下产生一个接口同名的java文件,点击进去发现里面的是我们写的接口,它里面有个Stub的子类,它继承了Bunle类并实现了我们的抱出去的接口里的方法,因此在服务里的onbind()返回去的Ibindl,实现该类的时候只需要继承Stub即可,在调用的应用程序里利用stub的asinstance方法实例将返回的Ibindle实例化成抛出的接口,利用这借口就可以调用服务里的方法了。
自动生成的Iservicemethod 接口
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\毕业设计\\adt-bundle-windows-x86_64-20140321\\workspace\\demoOnlyservice\\src\\com\\example\\demoonlyservice\\Iservicemethod.aidl
*/
package com.example.demoonlyservice;
public interface Iservicemethod extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.demoonlyservice.Iservicemethod
{
private static final java.lang.String DESCRIPTOR = "com.example.demoonlyservice.Iservicemethod";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.demoonlyservice.Iservicemethod interface,
* generating a proxy if needed.
*/
public static com.example.demoonlyservice.Iservicemethod asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.demoonlyservice.Iservicemethod))) {
return ((com.example.demoonlyservice.Iservicemethod)iin);
}
return new com.example.demoonlyservice.Iservicemethod.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_sayhello:
{
data.enforceInterface(DESCRIPTOR);
this.sayhello();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.demoonlyservice.Iservicemethod
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void sayhello() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_sayhello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void sayhello() throws android.os.RemoteException;
}
3、写一个类mybindle继承stub,在该类里调用服务里的方法来覆写接口里的方法,在onbindle里调用返回给开启服务的程序。
4 、在其他的应用程序里创建一个包名,注意包名必须与调用接口aidl所在的原应用程序里的包名相同,将源程序里的接口的aidl文件拷贝到包下,同源服务一样,应用程序下会自动生成aidl文件对应的包名和接口。再调用bindservice开启服务。
5、实现一个类myconnection,即开启服务的第二个参数,它需要实现ServiceConnection接口,实现接口方法,有方法onServiceConnected(ComponentName name, IBinder service),它是在连接服务成功后返回的Ibindle的时候执行,里面第二个参数就是返回的Ibinlde,它继承了Stub,通过stub里方法实例化service为接口IService = IService.Stub.asInterface(service),利用接口就可以调用服务里的方法。
注意:在运行的程序的时候发现,点击button响应事件startservice(View v)和startonlyservice(View v)时,在绑定服务了后,用接口调用远程服务方法时候,接口为空,就是说还没初始化。通过打印结果的顺序发现:点击事件执行完了才会去执行的回调事件,即onServiceConnected(ComponentName name, IBinder service)。我将绑定服务的代码移到oncreate方法在程序启动就绑定的服务,在点击事件里再通过接口调用服务里的方法就没错了。
打印的顺序: