天天看點

Android開發——四大元件之服務Service

<1>什麼是服務?

服務是四大元件之一,用于執行長期運作的任務,并且與使用者沒有互動

通俗來說就是長期于背景運作的程式(例如背景播放音樂,背景下載下傳檔案等)

<2>程序的概念

——android系統中程序分為以下幾種:

1,前台程序:顯示在最頂部的,直接跟使用者進行互動的,例如目前操作的activity界面

2,可見程序:可以看見,但不能操作,例如在一個actiivity的頂部彈出一個dialog,此時activity不能點選,但能被看見,就是可見程序

3,服務程序:在背景運作的程序

4,背景程序:隐退到背景,不做事的程序

5,空程序:沒有任何東西在上面跑,僅作為緩存作用, 目的是下次再啟動這個程序的時候會快一點

在手機上,如果按home鍵,目前的activity會退到背景,要麼成為背景程序,要麼成為服務程序

如果按傳回鍵,才會真正退出程式,成為空程序

因為隻有按傳回鍵activity才是調用了ondestory()方法真正銷毀

——如果手機此時記憶體不夠用了,會先殺死哪種程序?

首先殺死空程序,然後殺死背景程序,然後殺死服務,但服務被殺死後等待記憶體夠用時,服務又會重新運作

——service中是否可以執行耗時操作?

不可以

雖然服務是在背景運作的,但是service和activity都是運作在目前app所在的main thread(ui主線程)中的,而耗時操作(如網絡請求、拷貝資料、大檔案)會阻塞主線程,給使用者帶來不好的體驗

如果服務直接執行耗時操作,會出現anr,anr的意思是 android no response(無響應,操作逾時)

在android系統中 前台廣播的anr為10s,背景廣播為60s

activity的操作為5s 前台服務為20s,背景服務為200s

如果需要在服務中進行耗時操作,可以選擇 intentservice,intentservice是service的子類,用來處理異步請求

intentservice在oncreate()方法中通過handlerthread單獨開啟一個線程來處理intent請求對象所對應的任務,這樣可以避免事務處理阻塞主線程

onhandleintent()函數針對intent的不同進行不同的事務處理就可以,執行完一個intent請求對象所對應的工作之後,如果沒有新的intent請求達到,則自動停止service;

否則servicehandler會取得下一個intent請求傳入該函數來處理其所對應的任務

<3>服務的生命周期

因為服務一直都是不可見的,而且使用者無法進行互動操作,是以它的生命周期階段比較少

1,oncreat()

2,onstartcommand()(也可以用onstart(),但是onstart()已經過時了)

3,ondestroy()

服務的啟動和activity一樣,也有顯式意圖建立和隐式意圖建立

<4>第一種開啟服務的方式——startservice

首先建立一個類firstservice繼承自service

Android開發——四大元件之服務Service

 在acitivity界面通過顯式意圖(或隐式意圖)的方式來啟動服務和關閉服務

Android開發——四大元件之服務Service

<5>第二種開啟服務的方式——onbind綁定服務

假如我們想使用服務中的一個sayhello()方法,希望在服務運作過程中可以輸出一個hello

首先,在firstservice類中寫這個方法

Android開發——四大元件之服務Service

 然後,在mainactivity中new一個firstservice對象去調用這個方法

Android開發——四大元件之服務Service

 這樣可行嗎?

答案是不可以,這樣會提示如果要new firstservice調用sayhello方法,那麼這個方法必須是static

而如果把這個sayhello方法改為static,在firstservice類中又會提示擷取不到這個context

為什麼呢?因為四大元件其實都是由系統進行建立的,上下文context都是系統給它配置設定的,如果我們想直接new一個service是不可以的

如果我們想使用服務中的方法,那麼就需要用另一種開啟服務的方法——onbind

我們可以看到,onbind方法的傳回值是一個ibinder對象,是以我們要建立一個對象繼承ibinder作為onbind的傳回值

Android開發——四大元件之服務Service

 在這個傳回的innerbinder類的對象中我們就可以調用sayhello()方法了

在mainactivity中要做什麼呢?

首先是綁定服務

Android開發——四大元件之服務Service

 綁定的時候bindservice中第二個參數其實是缺少的,我們要建立一個serviceconnection對象

<code>第一個是參數是意圖對象,第二個參數是回調,第三個參數是标記,這個是自動建立的意思,如果服務沒有start,那麼會自己建立</code>

Android開發——四大元件之服務Service
Android開發——四大元件之服務Service

 然後是解綁服務

Android開發——四大元件之服務Service

最後,我們要使用服務中的sayhello方法,如何使用呢?

直接用綁定服務時建立的那個mremotebinder對象調用它裡面的callserviceinnermethod方法就好了

因為這個mremotebinder其實就是傳過來的innerbinder

Android開發——四大元件之服務Service

&lt;6&gt;兩種啟動方式的異同

bindservice的特點:

如果onbind()方法傳回的值為null,那麼onserviceconnected方法不會被調用

綁定服務和它所綁的acitivity是不求同生,但求同死的關系,如果activity沒了,那服務也要解綁

服務在解除綁定後會停止運作

綁定的服務隻能解綁一次,多次解綁會抛出異常

綁定的connection要和解鎖的connection對應,否則無法解綁

1,bindservice在系統設定裡的app界面下的running中是沒有顯示的;而startservice是有顯示的

2,startservice來啟動服務,服務是長期在背景運作的,隻有stopservice才會停止服務

就算你的activity都沒有了,這個service也還是在運作;

Android開發——四大元件之服務Service

而bindservice來啟動服務,随着activity的結束,它也會結束

是以在不用的時候要unbindservice,否則會導緻context洩露;

3,starservice不可以通訊(不能調用其中的方法);

而bindservice可以和服務進行通訊

&lt;7&gt;混合啟動服務

由于兩種啟動服務的方式各有優缺點,startservice啟動的服務可以長期背景運作,但不能跟服務進行通訊;bindservice啟動的服務不能長期背景運作,但可以和服務進行通訊

是以我們把兩種方法結合起來,建立一種既可以長期背景運作,又可以進行通訊的服務

startservice的服務的生命周期:oncreate-&gt;onstartcommand-&gt;ondestroy

bindservice的服務的生命周期:oncreate-&gt;onbind-&gt;onunbind-&gt;ondestroy

結合起來,startservice()-&gt;bindservice()-&gt;調用服務中的方法-&gt;unbindservice()-&gt;stopservice()

這樣就可以讓服務長期在背景運作,在解綁服務的時候,并沒有執行ondestroy方法,是以服務還是在運作着的

如果startservice()-&gt;bindservice()-&gt;stopservice()這樣是無法進行停止服務的

沒有解綁,就沒有辦法執行stopservice()方法

是以在實際開發中的流程是:

1,startservice開啟服務,為了使服務可以長期背景運作

2,bindservice拿到服務的控制binder,可以和服務進行通訊

3,調用服務裡的方法

4,unbindservice解綁服務,否則無法停止服務

(此時解綁了服務,但服務仍然在背景運作)

5,在不需要服務的時候停止服務stopservice