Android Service服务(二)AIDL

本文深入解析AIDL(Android Interface Definition Language)在Android平台上的作用及使用方法,包括服务端和客户端的实现步骤。重点讨论了如何在不同进程间通过AIDL进行高效通信,避免了内存空间访问限制,确保了跨进程对象传递的可行性。此外,文章还详细解释了AIDL使用过程中可能出现的安全异常及其解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    一、AIDL的作用

    由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。

    AIDL(Android Interface Definition Language)是一种IDL语言,用于成可以在Android设备上两个进程之间进行通信(interprocess communication,IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。

    注意:AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符。

    二、AIDL的使用步骤

    1、服务端代码:

     第一步:定义一个*.aidl文件,该文件是符合aidl语言定义规范的接口定义,里面定义了外部应用可以访问的方法。当我们保存该文件的时候,eclipse会自动在gen文件夹下生产一个相应的java接口文件。IPerson.aidl代码如下:

package com.example.server;
interface IPerson{
	void setValue(String name);
	String getValue();
}

     第二步:实现AIDL文件生成的JAVA接口Stub。Person.java实现Stub的代码如下:                                                                      

package com.example.server;

import com.example.server.IPerson;
import android.os.RemoteException;

public class Person extends IPerson.Stub{
	private String name;
	
	@Override
	public void setValue(String name) throws RemoteException {
		// TODO Auto-generated method stub
		this.name = name;
	}
	
	@Override
	public String getValue() throws RemoteException {
		// TODO Auto-generated method stub
		return this.name;
	}

      第三步:定义一个service,并将其注册到androidManifest.xml文件。示例代码如下:

package com.example.server;

import com.example.server.IPerson;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service{
	private IPerson.Stub iPerson = new Person();
	
	@Override
	public <span style="font-size:18px;">IBinder</span> onBind(Intent intent) {
		// TODO Auto-generated method stub
		return iPerson;
	}
}
<service android:name="MyService">
            <intent-filter>
                <action android:name="com.example.server.MyService"/>
            </intent-filter>
 </service>

         第四步:在本应用中的Activity中为自己定义的Service赋值。在实现了自己的Service时,为了其他应用可以通过bindService来和Service进行交互,我们要实现service中的onBind()方法,并且返回一个继承了Binder的内部类。AIDL要求我们,在这里不能再直接去实现Binder类了,而是去实现AIDL提供给我们的Stub类。实现stub类的同时,AIDL还要求我们同时实现我们在接口定义中的各种服务的具体实现。至此,我们的服务端已经和我们的aidl文件绑定到一起了。


 

package com.example.server;

import com.example.server.IPerson;
import com.example.server.R;

import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener{

	private Button bindButton;
	private Button unbindButton;
	private IPerson iPerson;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		bindButton = (Button)findViewById(R.id.button1);
		unbindButton = (Button)findViewById(R.id.button2);
		bindButton.setOnClickListener(this);
		unbindButton.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.button1:
			Intent intent = new Intent(MainActivity.this,MyService.class);
			bindService(intent, conn, Service.BIND_AUTO_CREATE);
			break;
		case R.id.button2:
			unbindService(conn);
			break;

		default:
			break;
		}
	}
	
	private ServiceConnection conn = new ServiceConnection() {
		//连接对象
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			iPerson = IPerson.Stub.asInterface(service);
			if(iPerson!=null){
				try {
					iPerson.setValue("AIDL TEST");
					Toast.makeText(MainActivity.this, "赋值成功", Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					Toast.makeText(MainActivity.this, "赋值失败", Toast.LENGTH_LONG).show();
				}
			}
		}
	};

}


      2、客户端代码:

        第一步:客户端要想使用该服务,首先要知道我们的服务在aidl文件中到底对外提供了什么服务。所以要将服务端的暴露的接口文件aidl文件拷贝一份到客户端的工程中(注意:aidl文件包的路径和服务端的一定要保持一致,否则会报错,报错见后面分析)。

     第二步:想要和service交互,我们要通过bindService方法,该方法有一个ServiceConnection类型的参数,而主要的代码便是在该接口中实现的。

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btn = (Button)findViewById(R.id.button1);
		btn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent();
				intent.setAction("com.example.server.MyService");
				bindService(intent, conn, Service.BIND_AUTO_CREATE);
			}
		});
	}
private ServiceConnection conn = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub		
		}
		
		@Override
		public synchronized void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			person = IPerson.Stub.asInterface(service);
			if(person != null){
				try {
					String name1 = person.getValue();
					Toast.makeText(MainActivity.this, "远程调用成功,值为:"+name1, Toast.LENGTH_LONG).show();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					Toast.makeText(MainActivity.this, "远程调用失败", Toast.LENGTH_LONG).show();
				}
			}
		}
	};

        三、报错的情况:java.lang.SecurityException: Binder invocation to an incorrect interface
      在使用AIDL远程服务时,经常会遇到上面的报错。发生这样的报错,最主要的原因是上面要注意的地方。也就是客户端的*.aidl文件的包路径与服务器端的包路径不一致导致的。

 

完整工程代码:http://download.youkuaiyun.com/detail/yegucheng2618/7802357

参考文章  http://blog.youkuaiyun.com/macdroid/article/details/8448742

                        http://blog.youkuaiyun.com/myxmu/article/details/7921521

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值