zoukankan      html  css  js  c++  java
  • Android跨进程訪问(AIDL服务)

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

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

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

    1、创建调用AIDL服务

    建立AIDL服务的步骤:

    第一步:在Eclipse的Androidproject的Java源文件文件夹中建立一个扩展名为aidl的文件。改文件的语法相似于Java代码,但稍有不同。

    第二步:假设aidl文件的内容是正确的。ADT会在gen文件夹下自己主动生成一个Java接口文件。

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

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

    第五步:在AndroidManifest.xml文件里配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是client要引用该服务的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>
    
    client代码:

    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文件,并使用Parcelablekeyword进行定义。

    看这个实例:

    在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();
    	}
    }
    
    在client实现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() + "
    ";
    					s += "Product.name = " + myService.getProduct().getName()
    							+ "
    ";
    					s += "Product.price = " + myService.getProduct().getPrice()
    							+ "
    ";
    					
    					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文件

    拷贝到你的project文件夹下。

    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服务的理解总结。希望对大家实用,欢迎共同学习和指导。




  • 相关阅读:
    DRF项目创建流程(1)
    RESTful API规范
    超哥笔记--shell 基本命令(4)
    转:django模板标签{% for %}的使用(含forloop用法)
    自定django登录跳转限制
    jquery Ajax应用
    js重定向跳转页面
    django项目mysql中文编码问题
    python进阶(六) 虚拟环境git clone报错解决办法
    Linux基础(六) Vim之vundle插件
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8662274.html
Copyright © 2011-2022 走看看