Android跨进程访问(AIDL服务)

我将AndroidAIDL的学习知识总结一下和大家共享

在Android开发中,AIDL主要是用来跨进程访问。

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信,一般是和Service服务组件一起使用来实现。

1、创建调用AIDL服务

建立AIDL服务的步骤:

第一步:在Eclipse的Android工程的Java源文件目录中建立一个扩展名为aidl的文件,改文件的语法类似于Java代码,但稍有不同。

第二步:如果aidl文件的内容是正确的,ADT会在gen目录下自动生成一个Java接口文件。

第三步:建立一个服务类(Service的子类)。

第四步:实现有aidl文件生成的Java接口。

第五步:在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。

下面实现了一个实例:

IMyService.aidl:(其实和Java类定义接口文件形式上有些类似)

package mobile.android.aidl;
interface IMyService
{
    String getValue();
}

实现的MyService.java类:

package mobile.android.aidl;
import mobile.android.aidl.IMyService;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService extends Service
{
	public class MyServiceImpl extends IMyService.Stub
	{
		@Override
		public String getValue() throws RemoteException
		{
			// TODO Auto-generated method stub
			return "《Android深度探索(卷1):HAL与驱动开发》";
		}
	}

	@Override
	public IBinder onBind(Intent intent)
	{
		return new MyServiceImpl();
	}
}

在AndroidManifest.xml的配置:

<service android:name=".MyService" >
<span style="white-space:pre">	</span><intent-filter>
		<action android:name="mobile.android.aidl.IMyService" />   <!--访问的ID-->
	</intent-filter>
</service>

客户端代码:

package mobile.android.aidlclient;
import mobile.android.aidl.IMyService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class Main extends Activity implements OnClickListener
{
	private IMyService myService = null;
	private Button btnInvokeAIDLService;
	private Button btnBindAIDLService;
	private TextView textView;
	private ServiceConnection serviceConnection = new ServiceConnection()
	{
		@Override
		public void onServiceConnected(ComponentName name, IBinder service)
		{
			myService = IMyService.Stub.asInterface(service);  //获取服务对象
			btnInvokeAIDLService.setEnabled(true);
		}

		@Override
		public void onServiceDisconnected(ComponentName name)
		{
			Toast.makeText(Main.this, "无法连接", Toast.LENGTH_SHORT).show();
			btnInvokeAIDLService.setEnabled(true);
		}
	};

	@Override
	public void onClick(View view)
	{
		switch (view.getId())
		{
			case R.id.btnBindAIDLService:
<span style="white-space:pre">				</span>//绑定AIDL服务
				if(!bindService(new Intent("mobile.android.aidl.IMyService"),
						serviceConnection, Context.BIND_AUTO_CREATE))
					Toast.makeText(Main.this, "无法连接", Toast.LENGTH_SHORT).show();
				break;

			case R.id.btnInvokeAIDLService:
				try
				{
					textView.setText(myService.getValue());
				}
				catch (Exception e)
				{
					textView.setText(e.getMessage());
				}
				break;
		}

	}  

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
		btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService);
		btnInvokeAIDLService.setEnabled(false);
		textView = (TextView) findViewById(R.id.textview);
		btnInvokeAIDLService.setOnClickListener(this);
		btnBindAIDLService.setOnClickListener(this);
	}
}

注意几点:

1、使用bindService方法绑定AIDL服务。其中需要使用Intent对象指定AIDL服务的ID,也就是声明服务时<action>标签中android:name的值。

2、在绑定时需要一个ServiceConnection对象。创建ServiceConnection对象的过程中如果绑定成功,系统会调用ServiceConnection.OnServiceConnected方法,

通过该方法的service参数值可获得AIDL服务对象。

2、传递复杂的数据的AIDL服务(自定义类型的数据)

首先,了解一下AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。

AIDL的支持数据类型如下:

1、Java的简单类型(int 、char、boolean),不需要Import导入。

2、String和CharSequence。不需要Import导入。

3、List和map。但是要注意,List和Map对象元素类型必须是AIDL服务支持的数据类型。不需要Import导入。

4、AIDL自动生成的接口。需要import导入。l

5、实现android.os.Parcelable接口的类。需要import导入。

在传递不需要Import导入的和上面说的一样,传递需要import导入的(实现android.os.Parcelable接口的类)。除了建立一个实现android.os.Parcelable的类

还要为这个类单独建立一个aidl文件,并使用Parcelable关键字进行定义。

看这个实例:

在AndroidManifest.xml的注册配置:

<service android:name=".MyService" >
	<intent-filter>
		<action android:name="mobile.android.complex.type.aidl.IMyService" />
	</intent-filter>
</service>

IMyService.aidl:

package mobile.android.complex.type.aidl;
import mobile.android.complex.type.aidl.Product;
interface IMyService
{
    Map getMap(in String country, in Product product);
    Product getProduct();
}          

Product.java类:

package mobile.android.complex.type.aidl;
import android.os.Parcel;
import android.os.Parcelable;

public class Product implements Parcelable
{
	private int id;
	private String name;
	private float price;
	public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>()
	{
		public Product createFromParcel(Parcel in)
		{
			return new Product(in);
		}

		public Product[] newArray(int size)
		{
			return new Product[size];
		}
	};
    public Product()
    {
    }
	private Product(Parcel in)
	{
		readFromParcel(in);
	}

	@Override
	public int describeContents()
	{
		// TODO Auto-generated method stub
		return 0;
	}

	public void readFromParcel(Parcel in)
	{
		id = in.readInt();
		name = in.readString();
		price = in.readFloat();
	}

	@Override
	public void writeToParcel(Parcel dest, int flags)
	{
		dest.writeInt(id);
		dest.writeString(name);
		dest.writeFloat(price);
	}

	public int getId()
	{
		return id;
	}

	public void setId(int id)
	{
		this.id = id;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public float getPrice()
	{
		return price;
	}

	public void setPrice(float price)
	{
		this.price = price;
	}
}

Product.aidl:(主要是在aidl中声明上面那个自定义的类型,才能在IMyService中使用)

parcelable Product;

MyService.java类:

package mobile.android.complex.type.aidl;
import java.util.HashMap;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService extends Service
{
	public class MyServiceImpl extends IMyService.Stub
	{

		@Override
		public Product getProduct() throws RemoteException
		{
			Product product = new Product();
			product.setId(1234);
			product.setName("汽车");
			product.setPrice(31000);
			return product;
		}

		@Override
		public Map getMap(String country, Product product)
				throws RemoteException
		{
			Map map = new HashMap<String, String>();
			map.put("country", country);
			map.put("id", product.getId());
			map.put("name", product.getName());
			map.put("price", product.getPrice());
			map.put("product", product);
			return map;
		}
	}

	@Override
	public IBinder onBind(Intent intent)
	{
		return new MyServiceImpl();
	}
}

在客户端实现AIDL服务:

package mobile.android.complex.type.aidlclient;
import mobile.android.complex.type.aidl.IMyService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Main extends Activity implements OnClickListener
{
	private IMyService myService = null;
	private Button btnInvokeAIDLService;
	private Button btnBindAIDLService;
	private TextView textView;
	private ServiceConnection serviceConnection = new ServiceConnection()
	{ 

		@Override
		public void onServiceConnected(ComponentName name, IBinder service)
		{
			myService = IMyService.Stub.asInterface(service);
			btnInvokeAIDLService.setEnabled(true);
		}

		@Override
		public void onServiceDisconnected(ComponentName name)
		{
			// TODO Auto-generated method stub
		}
	};

	@Override
	public void onClick(View view)
	{
		switch (view.getId())
		{
			case R.id.btnBindAIDLService:
				bindService(new Intent("mobile.android.complex.type.aidl.IMyService"),
						serviceConnection, Context.BIND_AUTO_CREATE);
				break;

			case R.id.btnInvokeAIDLService:
				try
				{
					String s = "";
					s = "Product.id = " + myService.getProduct().getId() + "\n";
					s += "Product.name = " + myService.getProduct().getName()
							+ "\n";
					s += "Product.price = " + myService.getProduct().getPrice()
							+ "\n";

					s += myService.getMap("China", myService.getProduct()).toString();
					textView.setText(s);
				}
				catch (Exception e)
				{
				}
				break;
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
		btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService);
		btnInvokeAIDLService.setEnabled(false);
		textView = (TextView) findViewById(R.id.textview);
		btnInvokeAIDLService.setOnClickListener(this);
		btnBindAIDLService.setOnClickListener(this);
	}
}

这边在实现一个扩展的:AIDL与来去电自动挂断

虽然可以同Activity Action来拨打电话,但是使用常规的方法无法挂断电话。不过使用Java反射技术是实现一种通过程序挂断电话的方法。

在Android SDK源生提供了如下接口:

com,android.internal,telephony.ITelephony,外部无法直接访问,这个接口提供了一个ITelephony.endCall的方法:

尽管不能直接访问ITelephony对象。不过在TelephonyManager类提供一个getITelepgony的方法可以返回一个ITelephony的对象。不过这个方法是私有的,但

我们可以通过Java的反射技术来调用该方法。在利用getITelephony获得ITelephony对象之前,先将Android SDK 目录下找到NeighboringCellInfo.aidl和ITelephony.aidl文件

复制到你的工程目录下。

ADT会根据ITelephony.aidl文件自动生成ITelephony.java文件。

下面是一个广播接收来电是先自动挂断指定电话的来电:

package mobile.android.call.aidl;
import java.lang.reflect.Method;
import com.android.internal.telephony.ITelephony;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class InCallReceiver extends BroadcastReceiver
{
	@Override
	public void onReceive(Context context, Intent intent)
	{
		TelephonyManager tm = (TelephonyManager) context
				.getSystemService(Service.TELEPHONY_SERVICE);
		switch (tm.getCallState())
		{
			case TelephonyManager.CALL_STATE_RINGING: // 响铃
				// 获得来电的电话号
				String incomingNumber = intent
						.getStringExtra("incoming_number");
				if ("12345678".equals(incomingNumber))
				{
					try
					{
						TelephonyManager telephonyManager = (TelephonyManager) context
								.getSystemService(Service.TELEPHONY_SERVICE);
						Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;
						Method telephonyMethod = telephonyManagerClass
								.getDeclaredMethod("getITelephony",
										(Class[]) null);
						telephonyMethod.setAccessible(true);
						ITelephony telephony = (com.android.internal.telephony.ITelephony) telephonyMethod
								.invoke(telephonyManager, (Object[]) null);
						telephony.endCall();
					}
					catch (Exception e)
					{
						Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
					}
				}
				break;
		}
	}
}

以上是对AIDL服务的理解总结,希望对大家有用,欢迎共同学习和指导。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 04:30:52

Android跨进程访问(AIDL服务)的相关文章

Android跨进程通信AIDL服务

服务(Service)是android系统中非常重要的组件.Service可以脱离应用程序运行.也就是说,应用程序只起到一个启动Service的作用.一但Service被启动,就算应用程序关闭,Service仍然会在后台运行. android系统中的Service主要有两个作用:后台运行和跨进程通讯.后台运行就不用说了,当Service启动后,就可以在Service对象中 运行相应的业务代码,而这一切用户并不会察觉.而跨进程通讯是这一节的主题.如果想让应用程序可以跨进程通讯,就要使用我们这节讲的

Android跨进程通信访问其他应用程序的Activity

访问其他应用程序的ActivityActivity既可以在进程内(同一个应用程序)访问,也可以跨进程访问.如果想在同一个应用程序中访问Activity,需要指定Context对象和Activity的Class对象,代码如下: Intent intent = new Intent(this, Test.class); startActivity(intent); Activity的跨进程访问与进程内访问略有不同.虽然它们都需要Intent对象,但跨进程访问并不需要指定Context对象和Activ

【朝花夕拾】性能优化篇之(八)AIDL与Android跨进程通信

一.Linux进程间通信 1.进程隔离 在操作系统中,进程与进程间的内存和数据都是不共享的.两个进程就好像大海中相互独立的两个岛屿,各自生活在互相平行的两个世界中,互不干扰,各自为政.这样做的目的,是为了避免进程间相互操作数据的现象发生,从而引起各自的安全问题.为了实现进程隔离,采用了虚拟地址空间,两个进程各自的虚拟地址不同,从逻辑上来实现彼此间的隔离. 马克思主义哲学说,人是一切社会关系的总和.任何一个个体都不可能完全隔离于外界,都不可避免地与外界"互通有无".进程也一样,时不时需要

Android跨进程通信

由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service. 其中Activity可以跨进程调用其他应用程序的Activity: Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然也可以对其他

android 跨进程通信

转自:http://www.androidsdn.com/article/show/137 由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service. 其中Activity可以跨进程调用其他应用程序的Activity: Content Pro

*Android跨进程通信的四种方式

由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service.其中Activity可以跨进程调用其他应用程序的Activity:Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应

【朝花夕拾】一篇文章搞懂Android跨进程通信

前言 只要是面试中高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Android开发高级工程师必须要跨过的一道坎.如果您还对这方面的知识还做不到如数家珍,那就和我一起来攻克它吧! 本文主要包含了如下内容: 其行文脉络大致如下,希望能加深读者对这方面内容的记忆:(1)Android基于Linux系统,所以先说系统进程相关知识和Linux IPC.(2)总结Android的IPC

C# HttpBrowser 跨进程访问,解决内存泄露问题

1 #undef DEBUG 2 using Microsoft.Win32; 3 using Newtonsoft.Json; 4 using System; 5 using System.Collections.Generic; 6 using System.Collections.Specialized; 7 using System.Diagnostics; 8 using System.Diagnostics.Contracts; 9 using System.Drawing; 10

Android 跨进程启动Activity黑屏(白屏)的三种解决方案

原文链接:http://www.cnblogs.com/feidu/p/8057012.html 当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面Lunacher启动一个App时也会出现相同情况,那是因为App冷启动也属于跨进程启动Activity.为什么没会出现这种情况呢?真正元凶就是Android创建进程需要准备很多资源,它是一个耗时的操作. 黑屏(白屏)原因 当A进程启动B进程中的一个Activity时,Android系统会先有zygo