android服务学习service之AIDL

            在android中,不同的应用运行在各自的进程中,互不干扰,一个进程也不能直接的去访问另一个进程的内存空间,因此,进程间通讯,android提供了AIDL这个工具来实现。

AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。AIDL IPC机制是面向接口的,更加轻量级。它是使用代理类在客户端和实现端传递数据

1.定义AIDL接口

其实,AIDL接口文件和普通的接口文件没有什么区别,只不过它的扩展名是.aidl罢了。因此同其它接口是一样的,只能是接口的声明和方法的声明,它还不能有static成员变量。编辑完成之后,它会自动在gen目录文件夹下自动生成IBinder接口文件。service必须实现这个IBinder接口,那么客户端才能绑定此service然后才能从IBinder中调用方法实现不同进程间的通讯。客户端要想绑定此service并且能顺利的实现通讯,必须要完整的拷贝一份AIDL接口,包括包名以及类名和所需要的其它东东,都必须是完全相同的拷贝,不能有一点差别。(暂时我的理解就是这样)AIDL声明接口的语法很是简单,只是用来描述参数以及返回值,甚至可以是其它的AIDL接口类型。不同的参数类型引用的时候是不一样的。如java数据的基本类(int,long,char,boolean)以及string和charSquence,list,map等是不需要import导入的;如果需要使用其它的AIDL接口以及实现了Parcelable接口的类,它们即使是在同一个包中,也是需要import的。还有就是,对于非java基本数据类型,包括string和charSquence,需要加上方向的指示(in,out,inout),in表示是由客户端设置,out表示服务器端设置,inout表示两端都可以进行设置

2.创建传递数据Bean--Student类

   Student是一个实现了Parcelable接口序列化的类,实现此接口必须要实现以下三个接口:

(1)writeToParcel(Parcel dest, int flags),将序列化存储的数据写入到外部提供的Parcel对象当中,以便读取。

(2)describeContents,网上叫内容接口描述,直接返回0即可,具体是干啥用的,反正我也不知道。

(3)static final Parcelable.Creator 对象 CREATOR,名字是固定的不可以更改。对应的两个接口分别是

createFromParcel(Parcel source):实现从source中创建出Bean实例的功能,如new Student(source)

newArray(int size):创建一个长度为size的类型为Bean的数组,如new Student[size]

(4)此外,既然数据能存了,还得必须能读出来啊,因此方法readFromParcel(Parcel in)这是可以要有的,读取

 的顺序与写入的顺序是一样一样的,不能有错。Student类如下: 

package com.dandy.AIDL;

import android.os.Parcel;
import android.os.Parcelable;

public class Student implements Parcelable {

	public static final int SEX_MALE = 1;

	public static final int SEX_FEMALE = 2;

	public int sno;
	public String name;
	public int sex;
	public int age;

	public Student() {
	}

	public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {

		@Override
		public Student createFromParcel(Parcel source) {
			return new Student(source);
		}

		@Override
		public Student[] newArray(int size) {
			return new Student[size];
		}
	};

	private Student(Parcel in) {
		readFromParcel(in);
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(sno);
		dest.writeString(name);
		dest.writeInt(sex);
		dest.writeInt(age);
	}

	public void readFromParcel(Parcel in) {
		sno = in.readInt();
		name = in.readString();
		sex = in.readInt();
		age = in.readInt();
	}
}

(5)实体类Student创建完成之后,需要创建Student.aidl文件,注意的是,这里的parcelable与实现的Parcelable是不一样的,

前者首字母p是小写,后者首字母P是大写,千万不要搞混咯。代码如下:

package com.dandy.AIDL;

parcelable Student;

简单得很,就一句话就完事了。

3.创建AIDL接口

     新建包:com.dandy.AIDL,然后在包中新建名为IMyService.aidl和IMyServiceResult.aidl的接口。如下:

package com.dandy.AIDL;

interface IMyServiceResult{
	void backResult(int result);
}
package com.dandy.AIDL;

import com.dandy.AIDL.Student;
import com.dandy.AIDL.IMyServiceResult;

interface IMyService{
	List<Student> getStudent();
	int addStudent(in Student student);
	void result(in IMyServiceResult resultService);
}

 

 IMyService是主体,既是让我们外部实现调用的,而IMyServiceResult是作为IMyService中的一个方法中的参数。

      4.实现接口

      创建一个服务类来实现刚才定义的IMyService.aidl接口,代码如下:

package com.dandy.service;

import java.util.ArrayList;
import java.util.List;
import com.dandy.AIDL.IMyService;
import com.dandy.AIDL.IMyServiceResult;
import com.dandy.AIDL.Student;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService extends Service{

	private List<Student> mStudents = new ArrayList<Student>();
	private static final String PACKAGE_SAYHI = "com.example.aidlclient"; 
	private boolean mCanRun = true;  
	private int counter = 0;
	private IMyServiceResult resultService;
	
	private final IMyService.Stub mBinder = new IMyService.Stub() {
		
		@Override
		public List<Student> getStudent() throws RemoteException {
			synchronized (mStudents) {
				return mStudents;
			}
		}
		
		@Override
		public int addStudent(Student student) throws RemoteException {
			if(!mStudents.contains(student)){
				 mStudents.add(student);
				 return 1;
			}
			return 0;
		}

		@Override
		public void result(IMyServiceResult resultService)throws RemoteException {
			MyService.this.resultService = resultService;
		};		
		
		/**
		 *权限验证
		 */
		@Override
		public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) 
				throws RemoteException {
			String packageName = null;
			String packages[] = MyService.this.getPackageManager().getPackagesForUid(getCallingUid());
			 if(packages != null && packages.length > 0) {  
	                packageName = packages[0];  
	         } 
			 
			 if(!PACKAGE_SAYHI.equals(packageName)){
				 return false;
			 }
			 return super.onTransact(code, data, reply, flags);  
		}
	};
	
	@Override
	public void onCreate() {
		Thread thread = new Thread(null,new ServiceWorkerTest(),"BackgroundServiceWorkerTest");
		thread.start();
		for (int i = 1; i < 6; i++) {  
            Student student = new Student();  
            student.name = "student:" + i;  
            student.age = i * 5;  
            mStudents.add(student);  
        }  
	};
	
	@Override  
    public void onDestroy(){  
        mCanRun = false;  
        super.onDestroy();  
    }  
	
	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	class ServiceWorkerTest implements Runnable {
		@Override
		public void run() {
			while (mCanRun) {
				if(resultService != null){
					try {
						resultService.backResult(counter);
					} catch (RemoteException e) {
						e.printStackTrace();
					}
				}
				counter++;
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}


在这里会看到一个IMyService.Stub类,这个类继承自IBinder类,也就是说这个MyService和普通的service 类没有区别,只不过这个这个类是返回的实现AIDL的IBinder对象。

(5)客户端获取,代码如下:

private final ServiceConnection mServiceConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			mIMyService = null;
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mIMyService = IMyService.Stub.asInterface(service);
		}
	};
MyService的绑定以及解绑与普通的Service没有区别。

(6)方法的调用

findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				try {
					Student student = mIMyService.getStudent().get(0);
					Log.i("TAG", "----->student:"+student.toString());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Student student = new Student();
				student.age = 100;
				student.name = "dandy";
				student.sex = Student.SEX_MALE;				
				try {
					int result = mIMyService.addStudent(student);
					Log.i("TAG", "------>result:"+result);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		});
		
		findViewById(R.id.result).setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				try {
					mIMyService.result(new IMyServiceResult.Stub() {
						
						@Override
						public void backResult(int result) throws RemoteException {
							Log.i("TAG", "--------------->result:"+result);
						}
					});
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		});


(7)AndroidManifest.xml中service配置

<service android:name="com.dandy.service.MyService"
            android:process=":remote"
            android:exported="true">
            <intent-filter >
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="com.dandy.service.MyService"/>  
            </intent-filter>
        </service>

android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",

没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。


注:以上内容结合了部分网络上资源内容,还望原著见谅!


资源文件下载。点击此处!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值