Android跨进程访问(AIDL服务)

来源:互联网 发布:c语言中gets的用法 编辑:程序博客网 时间:2024/05/14 18:28

我将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{@Overridepublic String getValue() throws RemoteException{// TODO Auto-generated method stubreturn "《Android深度探索(卷1):HAL与驱动开发》";}}@Overridepublic 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(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service){myService = IMyService.Stub.asInterface(service);  //获取服务对象btnInvokeAIDLService.setEnabled(true);}@Overridepublic void onServiceDisconnected(ComponentName name){Toast.makeText(Main.this, "无法连接", Toast.LENGTH_SHORT).show();btnInvokeAIDLService.setEnabled(true);}};@Overridepublic 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;}}  @Overridepublic 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);}@Overridepublic int describeContents(){// TODO Auto-generated method stubreturn 0;}public void readFromParcel(Parcel in){id = in.readInt();name = in.readString();price = in.readFloat();}@Overridepublic 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{@Overridepublic Product getProduct() throws RemoteException{Product product = new Product();product.setId(1234);product.setName("汽车");product.setPrice(31000); return product;}@Overridepublic 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;}}@Overridepublic 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(){ @Overridepublic void onServiceConnected(ComponentName name, IBinder service){myService = IMyService.Stub.asInterface(service);btnInvokeAIDLService.setEnabled(true);}@Overridepublic void onServiceDisconnected(ComponentName name){// TODO Auto-generated method stub}};@Overridepublic 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;}}@Overridepublic 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{@Overridepublic 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服务的理解总结,希望对大家有用,欢迎共同学习和指导。




1 0
原创粉丝点击