package com.ryg.sayhi.aidl; import com.ryg.sayhi.aidl.Student; interface IMyService { List<Student> getStudent(); void addStudent(in Student student); }說明:
package com.ryg.sayhi.aidl; parcelable Student;說明:這裏parcelable是個類型,首字母是小寫的,和Parcelable接口不是一個東西,要注意。
package com.ryg.sayhi.aidl; import java.util.Locale; import android.os.Parcel; import android.os.Parcelable; public final 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>() { public Student createFromParcel(Parcel in) { return new Student(in); } 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(); } @Override public String toString() { return String.format(Locale.ENGLISH, "Student[ %d, %s, %d, %d ]", sno, name, sex, age); } }說明:經過AIDL傳輸非基本類型的對象,被傳輸的對象須要序列化,序列化功能java有提供,可是android sdk提供了更輕量級更方便的方法,即實現Parcelable接口,關於android的序列化,我會在之後寫文章介紹。這裏只要簡單理解一下就行,大意是要實現以下函數
/** * @author scott */ public class MyService extends Service { private final static String TAG = "MyService"; private static final String PACKAGE_SAYHI = "com.example.test"; private NotificationManager mNotificationManager; private boolean mCanRun = true; private List<Student> mStudents = new ArrayList<Student>(); //這裏實現了aidl中的抽象函數 private final IMyService.Stub mBinder = new IMyService.Stub() { @Override public List<Student> getStudent() throws RemoteException { synchronized (mStudents) { return mStudents; } } @Override public void addStudent(Student student) throws RemoteException { synchronized (mStudents) { if (!mStudents.contains(student)) { mStudents.add(student); } } } //在這裏能夠作權限認證,return false意味着客戶端的調用就會失敗,好比下面,只容許包名爲com.example.test的客戶端經過, //其餘apk將沒法完成調用過程 public boolean onTransact(int code, Parcel data, 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]; } Log.d(TAG, "onTransact: " + packageName); if (!PACKAGE_SAYHI.equals(packageName)) { return false; } return super.onTransact(code, data, reply, flags); } }; @Override public void onCreate() { Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService"); thr.start(); synchronized (mStudents) { for (int i = 1; i < 6; i++) { Student student = new Student(); student.name = "student#" + i; student.age = i * 5; mStudents.add(student); } } mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); super.onCreate(); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, String.format("on bind,intent = %s", intent.toString())); displayNotificationMessage("服務已啓動"); return mBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { mCanRun = false; super.onDestroy(); } private void displayNotificationMessage(String message) { Notification notification = new Notification(R.drawable.icon, message, System.currentTimeMillis()); notification.flags = Notification.FLAG_AUTO_CANCEL; notification.defaults |= Notification.DEFAULT_ALL; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MyActivity.class), 0); notification.setLatestEventInfo(this, "個人通知", message, contentIntent); mNotificationManager.notify(R.id.app_notification_id + 1, notification); } class ServiceWorker implements Runnable { long counter = 0; @Override public void run() { // do background processing here..... while (mCanRun) { Log.d("scott", "" + counter); counter++; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }說明:爲了表示service的確在活着,我經過打log的方式,每2s打印一次計數。上述代碼的關鍵在於onBind函數,當客戶端bind上來的時候,將IMyService.Stub mBinder返回給客戶端,這個mBinder是aidl的存根,其實現了以前定義的aidl接口中的抽象函數。
<service android:name="com.ryg.sayhi.MyService" android:process=":remote" android:exported="true" > <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.ryg.sayhi.MyService" /> </intent-filter> </service>
說明:上述的 <action android:name="com.ryg.sayhi.MyService" />是爲了能讓其餘apk隱式bindService,經過隱式調用的方式來起activity或者service,須要把category設爲default,這是由於,隱式調用的時候,intent中的category默認會被設置爲default。html
import com.ryg.sayhi.aidl.IMyService; import com.ryg.sayhi.aidl.Student; public class MainActivity extends Activity implements OnClickListener { private static final String ACTION_BIND_SERVICE = "com.ryg.sayhi.MyService"; private IMyService mIMyService; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mIMyService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { //經過服務端onBind方法返回的binder對象獲得IMyService的實例,獲得實例就能夠調用它的方法了 mIMyService = IMyService.Stub.asInterface(service); try { Student student = mIMyService.getStudent().get(0); showDialog(student.toString()); } catch (RemoteException e) { e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (view.getId() == R.id.button1) { Intent intentService = new Intent(ACTION_BIND_SERVICE); intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE); } } public void showDialog(String message) { new AlertDialog.Builder(MainActivity.this) .setTitle("scott") .setMessage(message) .setPositiveButton("肯定", null) .show(); } @Override protected void onDestroy() { if (mIMyService != null) { unbindService(mServiceConnection); } super.onDestroy(); } }