Android使用AIDL(接口描述語言)設計和使用遠程接口

1 使用AIDL(AndRoid接口描述語言)設計和使用遠程接口 1.1 使用AIDL實現IPC 1.1.1 建立一個AIDL文件 1.1.2 實現接口 1.1.3 向客戶端公開接口 1.1.4 使用parcelables進行參數的值傳遞 1.2 調用一個IPC方法 使用AIDL(AndRoid接口描述語言)設計和使用遠程接口 Since each application runs in its own process, and you can write a service that runs in a different process from your Application's UI, sometimes you need to pass objects between processes. On the Android platform, one process can not normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and "marshall" the object across that boundary for you. 一般每一個應用程序都在它本身的進程內運行,但有時須要在進程間傳遞對象,你能夠經過應用程序UI的方式寫個運行在一個不一樣的進程中的 service。在AndRoid平臺中,一個進程一般不能訪問其餘進程中的內存區域。因此,他們須要把對象拆分紅操做系統能理解的簡單形式,以便假裝成對象跨越邊界訪問。 The code to do that marshalling is tedious to write, so we provide the AIDL tool to do it for you. 編寫這種假裝代碼至關的枯燥乏味,好在咱們提供了AIDL工具能夠來作這件事。 AIDL (Android Interface Definition Language) is an IDL language used to generate code that enables two processes on an Android device to talk using interprocess communication (IPC). If you have code in one process (for example, in an Activity) that needs to call methods on an object in another process (for example, a Service), you would use AIDL to generate code to marshall the parameters. AIDL(AndRoid接口描述語言)是一個IDL語言,它能夠生成一段代碼,可使在一個AndRoid設備上運行的兩個進程使用內部通訊進程進行交互。若是你須要在一個進程中(例如:在一個Activity中)訪問另外一個進程中(例如:一個Service)某個對象的方法,你就可使用 AIDL來生成這樣的代碼來假裝傳遞各類參數。 The AIDL IPC mechanism is interface-based, similar to COM or Corba, but lighter weight. It uses a proxy class to pass values between the client and the implementation. AIDL IPC的機制是基於接口的,和COM或Corba相似,但它是輕量級的。它使用代理類在客戶端和實現層間傳遞值。 This page includes the following main topics: 本頁包含如下主題: Implementing IPC Using AIDL Calling an .aidl (IPC) Class 使用AIDL實現IPC 調用一個AIDL(IPC)類 使用AIDL實現IPC Follow these steps to implement an IPC service using AIDL. 使用AIDL實現一個IPC有下列步驟: 1.Create your .aidl file - This file defines an interface (YourInterface.aidl) that defines the methods and fields available to a client. 一、建立你的AIDL文件 - 這個文件定義一個接口(YourInterface.aidl),該接口定義了可供客戶端訪問的方法和屬性。 2.Add the .aidl file to your makefile - (the Eclipse plugin manages this for you). Android includes the compiler, called AIDL, in the tools/ directory. 二、添加AIDL文件到你的makefile中-(Eclipse plugin能夠幫你管理)。AndRoid包括編譯器,AIDL調用,這些都能在tools/directory中找到。 3.Implement your interface methods - The AIDL compiler creates an interface in the Java programming language from your AIDL interface. This interface has an inner abstract class named Stub that inherits the interface (and implements a few additional methods necessary for the IPC call). You must create a class that extends YourInterface.Stub and implements the methods you declared in your .aidl file. 三、實現接口方法-AIDL編譯器從你的AIDL接口中使用JAVA編程語言來建立一個接口。這個接口有一個名爲Stub的內部抽象類,它繼承接口(並實現供IPC調用的所必需的幾個附加方法)。你必須建立一個類來實現該接口。 4.Expose your interface to clients - If you're writing a service, you should extend Service and override getBinder() to returning an instance of your class that implements your interface. 四、向客戶端開放接口-若是你寫個service,你應該擴展該Service並重載getBinder()方法來返回一個實現上述接口的類的實例。 [編輯] 建立一個AIDL文件 AIDL is a simple syntax that lets you declare an interface with one or more methods, that can take parameters and return values. These parameters and return values can be of any type, even other AIDL-generated interfaces. However, it is important to note that you must import all non-built-in types, even if they are defined in the same package as your interface. Here are the data types that AIDL can support: AIDL語法簡單,你能夠用來聲明一個帶一個或多個方法的接口,也能夠傳遞參數和返回值。這些參數和返回值能夠是任何類型,甚至是其餘的AIDL 生成的接口。然而,值得重視的是你必須導入全部的non-bult-in類型,即便他們已經做爲接口在其餘包裏定義了。下面是些AIDL支持的數據類型: Primitive Java programming language types (int, boolean, etc) — No import statement is needed. 簡單Java編程語言類型(int,boolean等) -不須要import聲明。 One of the following classes (no import statements needed): 下面類之一(不須要import聲明) Java 代碼 1. .String 2. .List - All elements in the List must be one of the types in this list, including other AIDL-generated interfaces 3. and parcelables. List may optionally be used as a "generic" class (e.g. List<String>). The actual concrete class 4. that the other side will receive will always be an ArrayList, although the method will be generated to use the 5. List interface. 6. .List - List 中的全部元素都必須是可支持的類型中的一個,包括其餘AIDL生成接口和parcelables。List能夠做爲泛型類來靈活使用(好比 7. List<String>)。 而實際的接受方的類則老是ArrayList,儘管該方法將被生成來使用List接口。 8. .Map - All elements in the Map must be of one of the types in this list, including other AIDL-generated interfaces 9. and parcelables. Generic maps, (e.g. of the form Map<String,Integer> are not supported. The actual concrete class 10. that the other side will receive will always be a HashMap,although the method will be generated to use the Map interface. 11. .Map - Map 中的全部元素都必須是可支持的類型中的一個,包括其餘AIDL生成接口和parcelables。泛型化的Maps(好比:Map<Stirng,Integer>)不被支持。 12. 而實際的接受方的類則老是 HashMap,儘管該方法將被生成去使用Map接口。 13. .CharSequence - This is useful for the CharSequence types used by TextView and other widget objects. 14. .CharSequence - CharSequence 的做用是能夠被TextView和其餘Widget對象使用。 .String .List - All elements in the List must be one of the types in this list, including other AIDL-generated interfaces and parcelables. List may optionally be used as a "generic" class (e.g. List<String>). The actual concrete class that the other side will receive will always be an ArrayList, although the method will be generated to use the List interface. .List - List中的全部元素都必須是可支持的類型中的一個,包括其餘AIDL生成接口和parcelables。List能夠做爲泛型類來靈活使用(好比 List<String>)。而實際的接受方的類則老是ArrayList,儘管該方法將被生成來使用List接口。 .Map - All elements in the Map must be of one of the types in this list, including other AIDL-generated interfaces and parcelables. Generic maps, (e.g. of the form Map<String,Integer> are not supported. The actual concrete class that the other side will receive will always be a HashMap,although the method will be generated to use the Map interface. .Map - Map中的全部元素都必須是可支持的類型中的一個,包括其餘AIDL生成接口和parcelables。泛型化的Maps(好比:Map<Stirng,Integer>)不被支持。 而實際的接受方的類則老是HashMap,儘管該方法將被生成去使用Map接口。 .CharSequence - This is useful for the CharSequence types used by TextView and other widget objects. .CharSequence - CharSequence的做用是能夠被TextView和其餘Widget對象使用。 Other AIDL-generated interfaces, which are always passed by reference. An import statement is always needed for these. Custom classes that implement the Parcelable protocol and are passed by value. An import statement is always needed for these. 其餘的AIDL生成接口經過引用方式進行傳遞。因此import聲明是必須的。封裝協議實現的自定義的類是值傳遞的方式。因此import聲明也是必須的。 Here is the basic AIDL syntax: 下面是基本的AIDL語法: Java 代碼 1. // My AIDL file, named SomeClass.aidl 2. // Note that standard comment syntax is respected. 3. // Comments before the import or package statements are not bubbled up 4. // to the generated interface, but comments above interface/method/field 5. // declarations are added to the generated interface. 6. // Include your fully-qualified package statement. 7. package com.google.android.sample; 8. // See the list above for which classes need 9. // import statements (hint--most of them) 10. import com.google.android.sample.IAtmService; 11. // Declare the interface. 12. interface IBankAccountService { 13. // Methods can take 0 or more parameters, and 14. // return a value or void. 15. int getAccountBalance(); 16. void setOwnerNames(in List<String> names); 17. // Methods can even take other AIDL-defined parameters. 18. BankAccount createAccount(in String name, int startingDeposit, in IAtmService atmService); 19. // All non-Java primitive parameters (e.g., int, bool, etc) require 20. // a directional tag indicating which way the data will go. Available 21. // values are in, out, inout. (Primitives are in by default, and cannot be otherwise). 22. // Limit the direction to what is truly needed, because marshalling parameters 23. // is expensive. 24. int getCustomerList(in String branch, out String[] customerList); 25. } // My AIDL file, named SomeClass.aidl // Note that standard comment syntax is respected. // Comments before the import or package statements are not bubbled up // to the generated interface, but comments above interface/method/field // declarations are added to the generated interface. // Include your fully-qualified package statement. package com.google.android.sample; // See the list above for which classes need // import statements (hint--most of them) import com.google.android.sample.IAtmService; // Declare the interface. interface IBankAccountService { // Methods can take 0 or more parameters, and // return a value or void. int getAccountBalance(); void setOwnerNames(in List<String> names); // Methods can even take other AIDL-defined parameters. BankAccount createAccount(in String name, int startingDeposit, in IAtmService atmService); // All non-Java primitive parameters (e.g., int, bool, etc) require // a directional tag indicating which way the data will go. Available // values are in, out, inout. (Primitives are in by default, and cannot be otherwise). // Limit the direction to what is truly needed, because marshalling parameters // is expensive. int getCustomerList(in String branch, out String[] customerList); } 實現接口 AIDL generates an interface file for you with the same name as your .aidl file. If you are using the Eclipse plugin, AIDL will automatically be run as part of the build process (you don't need to run AIDL first and then build your project). If you are not using the plugin, you should run AIDL first. AIDL生成一個接口文件,文件名和你的AIDL文件名一致。若是你使用的是Eclipse插件,AIDL會做爲build過程的一部分自動運行 (你不須要首先運行ADIL而後再去建立你的項目)。不然的話,你須要首先運行AIDL。 The generated interface includes an abstract inner class named Stub that declares all the methods that you declared in your .aidl file. Stub also defines a few helper methods, most notably asInterface(), which takes an IBinder (passed to a client's onServiceConnected() implementation when applicationContext.bindService() succeeds), and returns an instance of the interface used to call the IPC methods. See the section Calling an IPC Method for more details on how to make this cast. 生成的接口包括一個名爲Stub的內部抽象類,該類聲明瞭你在aidl文件中聲明的全部方法。Stub也定義幾個有用的方法,最特別的是 asInterface(),它執行一個IBinder(在 applicationContext.bindService()執行成功後傳給客戶端onServiceConnected()方法),並返回一個用來調用IPC方法的接口實例。更多細節請查看章節調用IPC方法。 To implement your interface, extend YourInterface.Stub, and implement the methods. (You can create the .aidl file and implement the stub methods without building between--the Android build process will process .aidl files before .java files.) 實現接口,擴展YourInterface.Stub,並實現方法成員。(你能夠建立一個aidl文件並實現stub方法而不用綁定 -AndRoid建立過程在java文件以前會處理aidl文件)。 Here is an example of implementing an interface called IRemoteService, which exposes a single method, getPid(), using an anonymous instance: 這裏有個例子,它實現了一個調用IRemoteService的接口,並使用匿名實例公開一個簡單的方法gerPid(): Java 代碼 1. // No need to import IRemoteService if it's in the same project. 2. private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){ 3. public int getPid(){ 4. return Process.myPid(); 5. } 6. } // No need to import IRemoteService if it's in the same project. private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){ public int getPid(){ return Process.myPid(); } } A few rules about implementing your interface: 實現接口時有幾個原則: Java 代碼 1. .No exceptions that you throw will be sent back to the caller. 2. . 拋出的異常不要返回給調用者。 3. .IPC calls are synchronous. If you know that an IPC service takes more than a few milliseconds to complete, 4. you should not call it in the Activity/View thread, because it might hang the application (Android might display 5. an "Application is Not Responding" dialog). Try to call them in a separate thread. 6. .IPC 調用是同步的。若是你知道一個IPC服務須要超過幾毫秒的時間才能完成地話,你應該避免在Activity/View線程中調用。 7. 因 爲它會掛起應用程序(AndRoid可能會顯示"應用程序沒有響應"對話框)。試着在一個獨立的線程中調用。 8. .Only methods are supported; you cannot declare static fields in an AIDL interface. 9. . 只有方法纔得到支持;你不能在AIDL接口中聲明靜態屬性。 .No exceptions that you throw will be sent back to the caller. .拋出的異常不要返回給調用者。 .IPC calls are synchronous. If you know that an IPC service takes more than a few milliseconds to complete, you should not call it in the Activity/View thread, because it might hang the application (Android might display an "Application is Not Responding" dialog). Try to call them in a separate thread. .IPC調用是同步的。若是你知道一個IPC服務須要超過幾毫秒的時間才能完成地話,你應該避免在Activity/View線程中調用。 由於它會掛起應用程序(AndRoid可能會顯示"應用程序沒有響應"對話框)。試着在一個獨立的線程中調用。 .Only methods are supported; you cannot declare static fields in an AIDL interface. .只有方法纔得到支持;你不能在AIDL接口中聲明靜態屬性。 向客戶端公開接口 Now that you've got your interface implementation, you need to expose it to clients. This is known as "publishing your service." To publish a service, inherit Service and implement getBinder() to return an instance of the class that implements your interface. Here's a code snippet of a service that exposes the IRemoteService interface to clients 如今你已完成了接口的實現,你須要向客戶端公開該實現。這就是咱們所熟悉的"發佈服務"。發佈一個Service,而後繼承 Service並實現getBinder()返回一個實現的類的實例。下面是個Service的代碼片段,該Service向客戶端公了 IRemoteService接口。 Java 代碼 1. public class RemoteService extends Service { 2. ... 3. @Override 4. public IBinder getBinder() { 5. return mBinder; 6. } 7. /** 8. * The IRemoteInterface is defined through IDL 9. */ 10. private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { 11. public int getPid() { 12. return Process.myPid(); 13. } 14. }; 15. } public class RemoteService extends Service { ... @Override public IBinder getBinder() { return mBinder; } /** * The IRemoteInterface is defined through IDL */ private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public int getPid() { return Process.myPid(); } }; } 使用parcelables進行參數的值傳遞 Java 代碼 1. Warning: Parcelables currently do not work if you're using the Eclipse plugin. You will see these errors if you try: 警 告:若是你如今使用Eclipse插件,Parcelables並不能工做。你會看到如下的錯誤信息: 2. 3. .aidl files that only declare parcelables don't need to go in the makefile 4. . 僅聲明parcelables的.aidl文件不須要寫進makefile 5. .aidl can only generate code for interfaces, not parcelables 6. .aidl 只能生成接口代碼,而不是parcelables。 7. 8. This is a known limitation. Parcelables can still be used with the ant build.xml files or your own custom build system. A workaround is for you to run the aidl tool by hand for all of your interfaces and add them to your Eclipse project. See step 5 below for why Eclipse shouldn't be trying to compile these aidl files. 9. 10. 這是個衆所周知的侷限。Parcelables仍然能夠被ant build的xml文件或自定義的build系統所使用。你應該在Eclipse項目中添加一個工做區,該工做區能夠爲全部的接口手動運行aidl工具。下面的步驟5說明爲什麼Eclipse不應嘗試編譯這些aidl文件。 Warning: Parcelables currently do not work if you're using the Eclipse plugin. You will see these errors if you try: 警告:若是你如今使用Eclipse插件,Parcelables並不能工做。你會看到如下的錯誤信息: .aidl files that only declare parcelables don't need to go in the makefile .僅聲明parcelables的.aidl文件不須要寫進makefile .aidl can only generate code for interfaces, not parcelables .aidl只能生成接口代碼,而不是parcelables。 This is a known limitation. Parcelables can still be used with the ant build.xml files or your own custom build system. A workaround is for you to run the aidl tool by hand for all of your interfaces and add them to your Eclipse project. See step 5 below for why Eclipse shouldn't be trying to compile these aidl files. 這是個衆所周知的侷限。Parcelables仍然能夠被ant build的xml文件或自定義的build系統所使用。你應該在Eclipse項目中添加一個工做區,該工做區能夠爲全部的接口手動運行aidl工具。下面的步驟5說明爲什麼Eclipse不應嘗試編譯這些aidl文件。 If you have a class that you would like to send from one process to another through an AIDL interface, you can do that. You must ensure that the code for your class is available to the other side of the IPC. Generally, that means that you're talking to a service that you started. 若是你有類須要經過AIDL接口從一個進程發送到另外一個,你必須確保類代碼能夠被IPC接收端所使用。一般這意味着一開始你就要和service 進行通信。 There are five parts to making a class support the Parcelable protocol: 讓類支持parcelable協議,有五點須要注意 1.Make your class implement the Parcelable interface. 1. 讓類實現Parcelable接口。 2.Implement the method public void writeToParcel(Parcel out) that takes the current state of the object and writes it to a parcel. 2. 實現public void writeToParcel(Parcel out),該方法能夠將當前對象的狀態寫入parcel. 3.Implement the method public void readFromParcel(Parcel in) that reads the value in a parcel into your object. 3. 實現public void readFromParcel(Parcel in),該方法能夠在 parcel中讀出值到對象中. 4.Add a static field called CREATOR to your class which is an object implementing the Parcelable.Creator interface. 4. 向類中添加一個靜態成員,名爲CREATOR。該對象實現了 Parcelable.Creator接口. 5.Last but not least, add an aidl file for your parcelable class so the AIDL tool can find it, but don't add it to your build. This file is used like a header file in C. You don't compile the aidl file for a parcelable just like you wouldn't normally compile a .h file. 5. 向parcelable類中添加一個.aidl文件,以便AIDl工具能夠找到。但不要向build中添加該文件。該文件的用法相似於C中的頭文件.你不須要爲parcelable編譯aidl文件,就像你不會編譯個.h文件同樣。 AIDL will use these methods and fields in the code it generates to marshall and unmarshall your objects. AIDL將使用代碼中生成的這些方法和成員來假裝或解讀對象。 Here is an example of how the Rect class implements the Parcelable protocol. 下面的例子說明了Rect類如何實現了Parcelable協議. Java 代碼 1. import android.os.Parcel; 2. import android.os.Parcelable; 3. public final class Rect implements Parcelable { 4. public int left; 5. public int top; 6. public int right; 7. public int bottom; 8. public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect> { 9. public Rect createFromParcel(Parcel in) { 10. return new Rect(in); 11. } 12. public Rect[] newArray(int size) { 13. return new Rect[size]; 14. } 15. }; 16. public Rect() { } 17. private Rect(Parcel in) { 18. readFromParcel(in); 19. } 20. public void writeToParcel(Parcel out) { 21. out.writeInt(left); 22. out.writeInt(top); 23. out.writeInt(right); 24. out.writeInt(bottom); 25. } 26. public void readFromParcel(Parcel in) { 27. left = in.readInt(); 28. top = in.readInt(); 29. right = in.readInt(); 30. bottom = in.readInt(); 31. } 32. } import android.os.Parcel; import android.os.Parcelable; public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect> { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in); } public void writeToParcel(Parcel out) { out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); } public void readFromParcel(Parcel in) { left = in.readInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); } } Here is Rect.aidl for this example 示例的Rect.aidl 1. package android.graphics; 2. // Declare Rect so AIDL can find it and knows that it implements 3. // the parcelable protocol. 4. parcelable Rect; package android.graphics; // Declare Rect so AIDL can find it and knows that it implements // the parcelable protocol. parcelable Rect; The marshalling in the Rect class is pretty simple. Take a look at the other methods on Parcel to see the other kinds of values you can write to a Parcel. Rect類中的假裝是至關簡單的。仔細看看Parcel中的其餘方法,你會看到其餘各類值你均可以寫進Parcel. Java 代碼 1. Warning: Don't forget the security implications of receiving data from other processes. In this case, the rect will read four numbers from the parcel, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. See Security and Permissions in Android for more on how to keep your application secure from malware. 2. 3. 警告:不要忽視從其餘進程接收數據時的安全性考慮。在本例中,rect將從parcel中讀四個數字,而你的工做則是確保這些都在可接受的值得範圍內而無論調用者想要幹什麼。AndRoid中的安全和訪問許可中有更多關於如何確保應用程序安全的信息。 Warning: Don't forget the security implications of receiving data from other processes. In this case, the rect will read four numbers from the parcel, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. See Security and Permissions in Android for more on how to keep your application secure from malware. 警告:不要忽視從其餘進程接收數據時的安全性考慮。在本例中,rect將從parcel中讀四個數字,而你的工做則是確保這些都在可接受的值得範圍內而無論調用者想要幹什麼。AndRoid中的安全和訪問許可中有更多關於如何確保應用程序安全的信息。 調用一個IPC方法 Here are the steps a calling class should make to call your remote interface: 調用類調用遠程接口的步驟: 1.Declare a variable of the interface type that your .aidl file defined. Java 代碼 1.聲明一個接口類型的變量,該接口類型在.aidl文件中定義。 2.Implement ServiceConnection. 2.實現ServiceConnection。 3.Call ApplicationContext.bindService(), passing in your ServiceConnection implementation. 3.調用ApplicationContext.bindService(),並在 ServiceConnection實現中進行傳遞. 4.In your implementation of ServiceConnection.onServiceConnected(), you will receive an IBinder instance (called service). Call YourInterfaceName.Stub.asInterface((IBinder)service) to cast the returned parameter to YourInterface type. 4.在ServiceConnection.onServiceConnected()實現中,你會接收一個IBinder實例(被調用的Service). 調用 YourInterfaceName.Stub.asInterface((IBinder)service) 將參數轉換爲YourInterface類型。 5.Call the methods that you defined on your interface. You should always trap DeadObjectException exceptions, which are thrown when the connection has broken; this will be the only exception thrown by remote methods. 5.調用接口中定義的方法。 你總會捕捉到DeadObjectException異常,該異常在鏈接斷開時被拋出。它只會被遠程方法拋出。 6.To disconnect, call ApplicationContext.unbindService() with the instance of your interface. 6. 斷開鏈接,調用接口實例中的 ApplicationContext.unbindService() A few comments on calling an IPC service: 調用IPC服務須要注意幾點: Java 代碼 1. .Objects are reference counted across processes. 2. 3. .You can send anonymous objects as method arguments. 4. . 匿名對象能夠經過方法參數發送。 .Objects are reference counted across processes. .You can send anonymous objects as method arguments. .匿名對象能夠經過方法參數發送。 Here is some sample code demonstrating calling an AIDL-created service, taken from the Remote Activity sample in the ApiDemos project. 下面的代碼展現了在ApiDemos項目從遠程Activity例子中調用AIDL建立Service的過程。 Java 代碼 1. public class RemoteServiceBinding extends Activity{ 2. IRemoteService mService = null; 3. Button mKillButton; 4. private boolean mIsBound; 5. @Override 6. protected void onCreate(Bundle icicle) { 7. super.onCreate(icicle); 8. setContentView(R.layout.remote_service_binding); 9. // Watch for button clicks. 10. Button button = (Button)findViewById(R.id.bind); 11. button.setOnClickListener(mBindListener); 12. button = (Button)findViewById(R.id.unbind); 13. button.setOnClickListener(mUnbindListener); 14. mKillButton = (Button)findViewById(R.id.kill); 15. mKillButton.setOnClickListener(mKillListener); 16. mKillButton.setEnabled(false); 17. } 18. private ServiceConnection mConnection = new ServiceConnection() { 19. public void onServiceConnected(ComponentName className, IBinder service) { 20. // This is called when the connection with the service has been 21. // established, giving us the service object we can use to 22. // interact with the service. We are communicating with our 23. // service through an IDL interface, so get a client-side 24. // representation of that from the raw service object. 25. mService = IRemoteService.Stub.asInterface((IBinder)service); 26. mKillButton.setEnabled(true); 27. // As part of the sample, tell the user what happened. 28. NotificationManager nm = (NotificationManager) 29. getSystemService(NOTIFICATION_SERVICE); 30. nm.notifyWithText(R.string.remote_service_connected, 31. getText(R.string.remote_service_connected), 32. NotificationManager.LENGTH_SHORT, 33. null); 34. } 35. public void onServiceDisconnected(ComponentName className) { 36. // This is called when the connection with the service has been 37. // unexpectedly disconnected -- that is, its process crashed. 38. mService = null; 39. mKillButton.setEnabled(false); 40. // As part of the sample, tell the user what happened. 41. NotificationManager nm = (NotificationManager) 42. getSystemService(NOTIFICATION_SERVICE); 43. nm.notifyWithText(R.string.remote_service_disconnected, 44. getText(R.string.remote_service_disconnected), 45. NotificationManager.LENGTH_SHORT, 46. null); 47. } 48. }; 49. private OnClickListener mBindListener = new OnClickListener() { 50. public void onClick(View v) { 51. // Establish a connection with the service, by its class name. 52. bindService(new Intent(RemoteServiceBinding.this, 53. RemoteService.class), 54. null, mConnection, Context.BIND_AUTO_CREATE); 55. mIsBound = true; 56. } 57. }; 58. private OnClickListener mUnbindListener = new OnClickListener() { 59. public void onClick(View v) { 60. if (mIsBound) { 61. // Detach our existing connection. 62. unbindService(mConnection); 63. mKillButton.setEnabled(false); 64. mIsBound = false; 65. } 66. } 67. }; 68. private OnClickListener mKillListener = new OnClickListener() { 69. public void onClick(View v) { 70. // To kill the process hosting our service, we need to know its 71. // PID. Conveniently our service has a call that will return 72. // to us that information. 73. if (mService != null) { 74. int pid = -1; 75. try { 76. pid = mService.getPid(); 77. } catch (DeadObjectException ex) { 78. // Recover gracefully from the process hosting the 79. // server dying. 80. // Just for purposes of the sample, put up a notification. 81. NotificationManager nm = (NotificationManager) 82. getSystemService(NOTIFICATION_SERVICE); 83. nm.notifyWithText(R.string.remote_call_failed, 84. getText(R.string.remote_call_failed), 85. NotificationManager.LENGTH_SHORT, 86. null); 87. } 88. if (pid > 0) { 89. // Go away! 90. Process.killProcess(pid); 91. } 92. } 93. } 94. }; 95. }
相關文章
相關標籤/搜索