service:
service运行在主ui线程,所以执行耗时操作要在线程中
应用场景:
用于后台数据处理(音乐播放器)
空服务(当内存不足时,不会优先关闭应用)
流氓软件(双服务)
aidl:
进程间的数据通信
首先创建一个AIDL_S项目,创建一个interface接口,定义接口,在把接口的后缀名改名为aidl,刷新项目即可,环境会自动根据aidl创建相应的java类(gen/com.aidl.remoteserver.IRemoteService.java)
com.aidl.remoteserver.IRemoteService.aidl
package com.aidl.remoteserver;
interface IRemoteService {
//获得id
int getId();
//获得自定义对象,在下面讲解如何把自定义对象作为通信数据
}
然后,创建一个服务
RemoteService.java
package com.aidl.remoteserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RemoteServer extends Service {
//会自动继承IBinder接口
private IRemoteService.Stub iRs = new IRemoteService.Stub() {
@Override
public int getId() throws RemoteException {
// TODO Auto-generated method stub
return 123;
}
};
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return iRs;
}
}
在AndroidManifest.xml中注册服务
<service
android:name="com.aidl.remoteserver.RemoteServer"
android:exported="true" //可以被外界调用
android:process=":remote"> //这个地方如果没有,那么同一个程序同时作为客户端/服务端的时候,iRs = IRemoteService.Stub.asInterface(service);这个地方会爆空指针异常
<intent-filter>
<action android:name="com.aidl.remoteserver"/>
</intent-filter>
</service>
创建AIDL_C项目,在该工程下创建和服务端一样的包,并把服务端的aidl复制到该包下(com.aidl.remoteserver.IRemoteService.aidl)
在MainActivity.java中调用远程服务,核心代码如下:
private static final String REMOTE_SERVICE_ACTION = "com.aidl.remoteserver";
Intent service = new Intent(REMOTE_SERVICE_ACTION);
bindService(service, conn, Context.BIND_AUTO_CREATE);
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
#mBackTextVeiw.setText("Disconnected");
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder service) {
iRs = IRemoteService.Stub.asInterface(service);
#isBind = true;
try {
int result = iRs.getId();
#mBackTextVeiw.setText("Result: " + result);
} catch (RemoteException e) {
Log.e("连接", "出错!");
#isBind = false;
e.printStackTrace();
}
}
};
记得在销毁的时候解绑服务
protected void onDestroy() {
if(isBind){
this.stopService(service);
}
super.onDestroy();
};
在上面IRemoteService.idle中有一个注释 //获得自定义对象
把自定义对象作为数据通信,需要
①让对象继承Parcelable接口,实现
//把需要序列化的数据写入到Parcel out对象中
public void writeToParcel(Parcel out, int arg1) {}
public int describeContents() {}两个函数
②创建一个public static final 修饰的Parcelable.Creator<T>对象,实现
//实现从Parcel source对象创建User对象的功能
@Override
public User createFromParcel(Parcel source) {
return null;
}
//创建一个类型为T,长度为size的数组(提供外部进行反序列化)
@Override
public User[] newArray(int size) {
return null;
}
例如:
User.java
package com.aidl.remoteserver;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable{
private int id;
private String name;
public User(){}
//构造函数,参数为Parcel对象
public User(Parcel in) {
// TODO Auto-generated constructor stub
readFromParcel(in);
}
private void readFromParcel(Parcel in) {
this.id = in.readInt();
this.name = in.readString();
}
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;
}
/* ----------------------- Parcelable接口函数 */
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
//把需要序列化的数据写入到Parcel out对象中
@Override
public void writeToParcel(Parcel out, int arg1) {
// TODO Auto-generated method stub
out.writeInt(id);
out.writeString(name);
}
/* ------------------------ */
public static final Parcelable.Creator<User> CREATOR = new Creator<User>() {
//实现从Parcel source对象创建User对象的功能
@Override
public User createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new User(source);
}
//创建一个类型为T,长度为size的数组(提供外部进行反序列化)
@Override
public User[] newArray(int size) {
// TODO Auto-generated method stub
return new User[size];
}
};
}
然后需要在User.java所在包下创建一个User.aidl
package com.aidl.remoteserver;
//Parcelable 的P更改为p,表示一种类型
parcelable User;
然后再IRemoteService.aidl中注释下加入
User getUser();
你会发现报错,原因是没有导包,import com.aidl.remoteserver.User;
如
package com.aidl.remoteserver;
import com.aidl.remoteserver.User;
interface IRemoteService {
//获得id
int getId();
//获得对象
User getUser();
}
最后把User.java,User.aidl,IRemoteService.aidl复制到AIDL_C的com.aidl.remoteserver包下
在MainActivity中就可以使用了
int result = iRs.getId();
User user = iRs.getUser();
#mBackTextVeiw.setText("Result: " + result + "\n" + user.getId() + " -- " + user.getName());
那么,如何限制其他应用调用该远程服务只让指定的应用调用?
只需要在服务端的IRemoteService.Stub的实现中重写onTransact方法做限制即可
RemoteServer.java
public class RemoteServer extends Service {
...
protected String PACKAGE_NAME_PASS = "com.aidl.client";
private IRemoteService.Stub iRs = new IRemoteService.Stub() {
@Override
public int getId() throws RemoteException {
// TODO Auto-generated method stub
return 123;
}
@Override
public User getUser() throws RemoteException {
// TODO Auto-generated method stub
User user = new User();
user.setId(11235);
user.setName("hello kitty");
return user;
}
//在这里做权限认证,return false表示客户端调用远程服务失败,假设允许包名为"com.aidl.client"的客户端通过
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException {
String packageName = null;
String[] packagesForUid = RemoteServer.this.getPackageManager().getPackagesForUid(getCallingUid());
if(packagesForUid != null && packagesForUid.length > 0){
packageName = packagesForUid[0];
}
if(!packageName.equals(PACKAGE_NAME_PASS )){
return false;
}
return super.onTransact(code, data, reply, flags);
};
};
...
}
网友评论