远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:
- android支持String和CharSequence直接跨进程传送
- 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
- android允许传递实现Parcelable接口的类,需要import;
- android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import
- 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
看一个实例:
定义一个Person类 它实现了 Parcelable接口
package com.syh;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
private int age;
private String name;
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
return new Person(source);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public Person() {
}
private Person(Parcel in) {
readFromParcel(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
}
public void readFromParcel(Parcel in) {
age = in.readInt();
name = in.readString();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
定义一个对应的aidl文件,项目中每个Parcelable 都需要一个 .aidl文件:
package com.syh;
parcelable Person;
现在在远程服务中使用Person类IStockQuoteService,接受类型为Person的输入参数。思路是,客户端将Person传递给服务,告诉它谁请求了报价。新的 IStockQuoteService.aidl文件内容如下:是 .aidl文件不是java文件
package com.syh;
import com.syh.Person;
interface IStockQuoteService
{
String getQuote(in String ticker, in Person requester);
}
getQuote()方法现在接受两个参数:股票代号和Person,后者指定谁发出了请求。请注意,我们在参数上包含了方向指示符,因为这些参数属于非原语类型,我们还为Person类提供了一条 Import语句。Person类与服务定义位于同一个包中 (com.syh)。
服务类 StockQuoteService2.java:
package com.syh;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class StockQuoteService2 extends Service {
private NotificationManager notificationMgr;
public class StockQuoteServiceImpl extends IStockQuoteService.Stub {
@Override
public String getQuote(String ticker, Person requester)
throws RemoteException {
return "Hello" + requester.getName() + "! Quote for " + ticker
+ " is 20.0";
}
}
@Override
public void onCreate() {
super.onCreate();
notificationMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage("onCreate() called in StockQuoteService2");//通知栏
}
@Override
public void onDestroy() {
displayNotificationMessage("on Destroy() called in StockQuoteService2");
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
displayNotificationMessage("onBind() called in StockQuoteService2");
return new StockQuoteServiceImpl();
}
private void displayNotificationMessage(String message) {
Notification notification = new Notification(R.drawable.emblem_note,
message, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
notification.setLatestEventInfo(this, "StockQuoteService2", message,
contentIntent);
notificationMgr.notify(R.id.app_notification_id, notification);
}
}
客户端的我们的MainActivity类 :
package com.sayed;
import com.syh.IStockQuoteService;
import com.syh.Person;
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.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String TAG = "StockQuoteClient2";
private IStockQuoteService stockService = null;
private Button bindBtn = null;
private Button callBtn = null;
private Button unbindBtn = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bindBtn = (Button) findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
bindService(new Intent(IStockQuoteService.class.getName()),
serConn, Context.BIND_AUTO_CREATE);
bindBtn.setEnabled(false);
callBtn.setEnabled(true);
unbindBtn.setEnabled(true);
}
});
callBtn = (Button) findViewById(R.id.callBtn);
callBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
callService();
}
});
callBtn.setEnabled(false);
unbindBtn = (Button) findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serConn);
bindBtn.setEnabled(true);
callBtn.setEnabled(false);
unbindBtn.setEnabled(false);
}
});
}
private void callService() {
try {
Person person = new Person();
person.setAge(33);
person.setName("Sayed");
String response = stockService.getQuote("GOOG", person);
Toast.makeText(this, "Value from service is " + response,
Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
Log.e("MainActivity", e.getMessage(), e);
}
}
private ServiceConnection serConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v(TAG, "onServiceConnected() called");
stockService = IStockQuoteService.Stub.asInterface(service);
callService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v(TAG, "onServiceDisconnected() called");
stockService = null;
}
};
}
把服务端的 Person.java、IStockQuoteService.aidl、Person.aidl文件复制到客户端的com.sayed 包下。
为了避免大家把 .aidl文件放错位置, 来2张项目截图,请大家找准位置,看准包名。
客户端
服务端