调用远程服务里的方法service,进程间通信adil的学习

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方法在程序启动就绑定的服务,在点击事件里再通过接口调用服务里的方法就没错了。

打印的顺序:

 

posted @ 2015-08-16 10:35  Lammy  阅读(1622)  评论(0编辑  收藏  举报