天天看點

Android面試系列之二

11, 談談對service的了解?

Service,服務。幕後工作者,甘心做綠葉。默默為前台提供支援。Android的核心三元件可以通過電視台進行比喻,電視播放畫面可以看作Activity,使用者可以通過遙控器切換不同的電視台可以看做是不同Activity之間的切換。電視播放的新聞可以看做是廣播發送方,每個觀衆都是接收者。而電視幕後工作者可以看做是Service,從不抛頭露面。默默為Activity提供所需要的内容。

說到Service,我們最熟悉莫過于windows中的服務。他們都是在背景長時間運作,接受上層指令,完成相關操作。但android中的service與其他的服務還是有所差别的,service與其他三個元件一樣,其程序模型都是可以通過XML進行配置的。調用方和釋出方都可以有權利來選擇是把這個元件運作在同一個程序下,還是不同的程序下。如果一個Service,是有期望運作在于調用方不同程序的時候,就需要利用Android提供的RPC(Remote Procedure Call Protocol)機制,為其部署一套程序間通信的政策。當然這些政策android已經為你封裝好了。你需要了解底層。直接拿來使用即可。RPC其實就是代理模式的一種實作,在調用端和服務端都去生成一個代理類,做一些序列化和反序列化的事情,使得調用端和伺服器端都可以像調用一個本地接口一樣使用RPC接口。

Android中用來做資料序列化的類是Parcel,封裝了序列化的細節,向外提供了足夠對象化的通路接口

AIDL (Android Interface Definition Language) ,一種接口定義的語言,服務的RPC接口,可以用AIDL來描述, ADT幫助你自動生成一整套的代理模式需要用到的類,不要要你自己寫。下面會給個例子。

12, service的生命周期?

在有生命周期的這幾個元件中,Service的生命周期最長,其次是Activity最後Receiver。

Service的生命周期相對Activity簡單一些。Service提供了兩種啟動service的方式,每一種方式對應一套生命周期方法。以下是android提供的圖檔:

Android面試系列之二

1)  以startService()方式啟動的服務,它的生命周期如下:

onCreate()->onStartCommand()這時服務已經開啟,如果再點選一下啟動則隻會調用onStartCommand()。這說明service是單例的,隻執行個體化一次。點選停止按鈕調用onDestroy()。銷毀。生命周期完成。以下為圖示:

Android面試系列之二

2)  以bindService()方式啟動服務。調用方式如下:

onCreate()->onBind() 此時服務綁定。再次綁定則無響應。解除綁定:onUnbind()->onDestroy()。生命周期完成。如圖所示:

Android面試系列之二

  13, 啟動service的兩種方法?有什麼差別?

一種是startService(),另一種是bindService()。這兩者的差別是第一種方式調用者開啟了服務,即會與服務失去聯系,兩者沒有關聯。即使通路者退出了,服務仍在運作。如需解除服務必須顯式的調用stopService方法。主要用于調用者與服務沒有互動的情況下,也就是調用者不需要擷取服務裡的業務方法。比如電話錄音。而後者調用者與服務綁定在一起的。當調用者退出的時候,服務也随之退出。用于需要與服務互動。

14, 實作程序内與程序間通信是怎麼實作的?

在linux中程序通信機制有很多種,比如:消息隊列(message queue),socket,共享記憶體(share mermory)等等。但是在Android中,無論是程序内還是程序間,所采用的通信機制,主要是以Binder為核心。Android之是以選擇是Binder作為程序的通信機制,主要是Binder與其他通信方式相比更加快速和簡潔,所消耗的記憶體也是相對較少。當然也有其他方面的原因,比如傳統程序通信有可能會增加程序開銷,也有安全方面的風險。Binder能解決這些問題。故成為首選的通信方式。

1)  程序内的通信,與程序間的通信相比,相對容易些。程序内通信肯定要采用綁定的方式開啟服務。這樣才能與服務進行互動。綁定服務的方法:

bindService(Intent service, ServiceConnection conn, int flags)

這個方法的第一個參數很好了解。用于激活哪個服務,第二個參數是關鍵,服務的連接配接,這是一個接口,用于接收服務開啟或者關閉時傳回的資料。實作這個接口要重寫兩個方法:

onServiceConnected(ComponentName name, IBinder service):一旦用戶端與服務端綁定成功,将有這個方法的第二個參數接收服務端傳回的IBinder對象。得到服務端的引用就可以在用戶端調用服務裡的一些業務方法。這也是程序内通信的主要部分。

onServiceDisconnected(ComponentName name):這個方法在服務斷開是調用,服務被銷毀或者被幹掉時調用。附件處有例子。

2)  程序之間的通信,其主要的核心機制同樣是Binder。其實Binder底層就是通過Parcel(郵包)來完成資料傳輸的。程序内通信可以通過IBinder對象來實作業務共享的,但是程序間的通信這種方式就肯定不行了。這時就用到了AIDL。

AIDL是一種接口定義語言,用于限制兩個程序間的通訊規則,供編譯器生成代碼,實作Android裝置上的兩個程序間通信(IPC).AIDL的IPC機制和EJB所采用的CORBA很類似,程序之間的通信資訊,首先會被轉換成AIDL協定消息,然後發送給對方,對方收到AIDL協定消息後再轉換成相應的對象.由于程序之間的通信資訊需要雙向轉換,是以android采用代理類在背後實作了資訊的雙向轉換,代理類由android編譯器生成,對開發人員來說是透明的.

使用方式如下:

定義AIDL. //XXXService.aidl,注意擴充名

package com.iteye.androidtoast;

interface XXXService {

  void sayHello(in/out/inout String name);//in|out|inout是參數的方向

}

ide會自動在gen包下生成對應的java類,接口檔案中生成一個Stub的抽象類,裡面包括aidl定義的方法,還包括一些其它輔助方法.值得關注的是asInterface(IBinder iBinder),它傳回接口類型的執行個體,對于遠端服務調用,遠端服務傳回給用戶端的對象為代理對象,用戶端onServiceConnected(ComponentName name, IBinder service)方法引用該對象時不能直接強轉成接口類型的執行個體,而應該使用asInterface(IBinder iBinder)進行類型轉換.

AIDL定義注意事項:

(1)接口名和aidl檔案名相同.

(2)接口和方法前不用加通路權限修飾符public,private,protected等,也不能用final,static.

(3)AIDL預設支援的類型包話java基本類型(int,long,boolean等)和(String,List,Map,

  CharSequence),使用這些類型時不需要import聲明.對于List和Map中的元素類型必須是AIDL支援的類型.如果使用自定義類型作為參數或傳回值,自定義類型必須實作Parcelable接口.

  (4)自定義類型和AIDL生成的其它接口類型在aidl描述檔案中,應該顯式import,即便在該類和定義的包在同一個包中.

  (5)在aidl檔案中所有非Java基本類型參數必須加上in、out、inout标記,以指明參數是輸入參數、輸出參數還是輸入輸出參數.

  (6)Java原始類型預設的标記為in,不能為其它标記.

具體步驟:

1.建立伺服器android項目(server)

2.建立服務類.CustomerService

              public class CustomerService extends Service {

                     ...

              }

 3.配置清單注冊服務類

              <!-- 注冊服務 -->

        <service android:name=". CustomerService " />

4.定義aidl檔案.

              ICustomerService.aidl

              package com.iteye.androidtoast.aidl;

              interface ICustomerService {

                     String sayHello(String name);

              }

 5.ide在gen目錄下自動生成java接口.

 6.需要實作CustomerService.onBind()方法的傳回值.

              public IBinder onBind(Intent intent) {

                     return new ICustomerService.Stub() {

                            public String sayHello(String name) throws RemoteException {

                                   return "hello " + name;

                            }

                     };

              }

   7.建立用戶端項目(android項目)

   8.複制服務端項目aidl檔案到用戶端(連同包結構一同複制),同樣在用戶端項目中

         也會生成對應的接口類.同步驟(5).

   9.綁定服務.

              class CustomerConnection implements ServiceConnection{

                     public void onServiceConnected(ComponentName name, IBinder service) {

                            is = ICustomerService.Stub.asInterface(service);

                     }

                     public void onServiceDisconnected(ComponentName name) {

                     }

              }

   10.綁定服務

              Intent i = new Intent();

              i.setAction(“”)

              this.bindService(i, conn, BIND_AUTO_CREATE);

  11,調用遠端服務方法