日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Service的理解和使用

發布時間:2025/6/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Service的理解和使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先推薦一下郭林大神所講的這一節的博客:http://blog.csdn.net/guolin_blog/article/details/11952435
下面結合我對這一部分的學習,自己做一個小節。
Android5.0之后組件必須使用顯示intent來啟動,如果為隱示的,則設置Intent的包名。intent.setPackage(“com.llay.admin.mydemo”);

一、基本概念

Service是一個應用程序組件,它能夠在后臺執行一些耗時較長的操作,并且不提供用戶界面。服務能被其它應用程序的組件啟動,即使用戶切換到另外的應用時還能保持后臺運行。此外,應用程序組件還能與服務綁定,并與服務進行交互,甚至能進行進程間通信(IPC)。 比如,服務可以處理網絡傳輸、音樂播放、執行文件I/O、或者與content provider進行交互,所有這些都是后臺進行的。

二、服務的分類

服務有以下兩種基本類型:

Started (這里有一個service的子類IntentService,待會兒單獨講解)
如果一個應用程序組件(比如一個activity)通過調用startService()來啟動服務,則該服務就是被“started”了。一旦被啟動,服務就能在后臺一直運行下去,即使啟動它的組件已經被銷毀了。
通常,started的服務執行單一的操作并且不會向調用者返回結果。比如,它可以通過網絡下載或上傳文件。當操作完成后,服務應該自行終止。

Bound
如果一個應用程序組件通過調用bindService()綁定到服務上,則該服務就是被“bound”了。bound服務提供了一個客戶端/服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至可以利用進程間通信(IPC)跨進程執行這些操作。綁定服務的生存期和被綁定的應用程序組件一致。
多個組件可以同時與一個服務綁定,不過所有的組件解除綁定后,服務也就會被銷毀。

三、一些回調方法

服務的生命周期圖:

為了創建一個服務,你必須新建一個Service的子類(或一個已有Service的子類)。在你的實現代碼中,請按需重寫一些回調方法,用于對服務生命周期中的關鍵節點進行處理,以及向組件提供綁定機制。 最重要的需要重寫的回調方法包括:

onStartCommand()
當其它組件,比如一個activity,通過調用startService()請求started方式的服務時,系統將會調用本方法。 一旦本方法執行,服務就被啟動,并在后臺一直運行下去。 如果你的代碼實現了本方法,你就有責任在完成工作后通過調用stopSelf()或stopService()終止服務。 (如果你只想提供bind方式,那就不需要實現本方法。)

onBind()
當其它組件需要通過bindService()綁定服務時(比如執行RPC),系統會調用本方法。 在本方法的實現代碼中,你必須返回IBinder來提供一個接口,客戶端用它來和服務進行通信。 你必須確保實現本方法,不過假如你不需要提供綁定,那就返回null即可。

onCreate()
當服務第一次被創建時,系統會調用本方法,用于執行一次性的配置工作(之前已調用過onStartCommand()或onBind()) 了。如果服務已經運行,則本方法就不會被調用。

onDestroy()
當服務用不上了并要被銷毀時,系統會調用本方法。 你的服務應該實現本方法來進行資源的清理工作,諸如線程、已注冊的偵聽器listener和接收器receiver等等。 這將是服務收到的最后一個調用。

如果組件通過調用startService()(這會導致onStartCommand()的調用)啟動了服務,那么服務將一直保持運行,直至自行用stopSelf()終止或由其它組件調用stopService()來終止它。

如果組件調用bindService()來創建服務(那onStartCommand()就不會被調用),則服務的生存期就與被綁定的組件一致。一旦所有客戶端都對服務解除了綁定,系統就會銷毀該服務。

僅當內存少得可憐、且必須覆蓋擁有用戶焦點的activity的系統資源時,Android系統才會強行終止一個服務。 如果服務被擁有用戶焦點的activity綁定著,則它一般不會被殺死。 如果服務聲明為#在前臺運行服務(下文討論),則它幾乎永遠不會被殺死。 否則,如果服務已被啟動并且已運行了很長時間,那么系統將會隨時間推移而降低它在后臺任務列表中的級別, 此類服務將很有可能會被殺死——如果服務已經啟動,那你必須好好設計代碼,使其能完美地應付被系統重啟的情況。 如果系統殺死了你的服務,只要資源再度夠用,系統就會再次啟動服務(當然這還取決于onStartCommand()的返回值,下文將會述及)。關于系統可能會在何時銷毀服務的詳細信息,請參閱進程和線程。

四、代碼的實現

注意:Service是Android的四大組件,所以記得在Androidmanifests.xml文件中注冊。注意:四大組件只有BroadCast能動態注冊。

界面圖片:

4、1 Started服務的代碼實現

started服務是指其它組件通過調用startService()來啟動的服務,這會引發對該服務onStartCommand()方法的調用。

一旦服務被啟動started,它就擁有了自己的生命周期,這是獨立于啟動它的組件的。并且它能夠在后臺一直運行下去,即使啟動它的組件已被銷毀 也是如此。 因此,服務應該能夠在完成工作后自行終止,通過調用stopSelf()即可,或者由其它組件通過調用stopService()也可以。

諸如activity之類的應用程序組件,可以通過調用startService()啟動服務,并傳入一個給出了服務和服務所需數據的Intent對象。服務將在onStartCommand()方法中接收到該Intent對象。

舉個例子,假定某activity需要把一些數據保存到在線數據庫中。此activity可以啟動一個守護服務并通過傳入startService()一個intent把需要保存的數據發送給該服務。該服務在onStartCommand()內接收intent,連接Internet,再進行數據庫事務處理。當事務完成后,服務自行終止,并被系統銷毀。

在Activity中代碼的方法:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initStartedService</span>() {<span class="hljs-keyword">final</span> Intent intent = <span class="hljs-keyword">new</span> Intent(ServiceDemoActivity.<span class="hljs-keyword">this</span>, HelloStartedService.class);startedService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(startedServiceTAG, <span class="hljs-string">"開啟服務"</span>);intent.putExtra(<span class="hljs-string">"StartedServiceTest"</span>, <span class="hljs-string">"StartedServiceTest"</span>);startService(intent);}});stopService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(stopServiceTAG, <span class="hljs-string">"手動停止服務"</span>);stopService(intent);}});}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

HelloStartedService.java文件

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloStartedService</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Service</span> {</span><span class="hljs-keyword">private</span> Looper looper;<span class="hljs-keyword">private</span> StartedServiceHandler startedServiceHandler;<span class="hljs-keyword">public</span> String s;<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> String TAG = <span class="hljs-string">"startedService"</span>;<span class="hljs-keyword">public</span> <span class="hljs-title">HelloStartedService</span>() {}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>() {<span class="hljs-comment">//這里配置一些信息</span><span class="hljs-comment">//啟動運行服務的線程。</span><span class="hljs-comment">//請記住我們要創建一個單獨的線程,因為服務通常運行于進程的主線程中,可我們不想阻塞主線程。</span><span class="hljs-comment">//我們還要賦予它后臺運行的優先級,以便計算密集的工作不會干擾我們的UI。</span>HandlerThread handlerThread = <span class="hljs-keyword">new</span> HandlerThread(<span class="hljs-string">"StartedService"</span>);handlerThread.start();<span class="hljs-comment">//獲得HandlerThread的Looper隊列并用于Handler</span>looper = handlerThread.getLooper();startedServiceHandler = <span class="hljs-keyword">new</span> StartedServiceHandler(looper);Log.e(TAG, <span class="hljs-string">"onCreate"</span>);}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">onStartCommand</span>(Intent intent, <span class="hljs-keyword">int</span> flags, <span class="hljs-keyword">int</span> startId) {Log.e(TAG, <span class="hljs-string">"onStartCommand"</span>);s = intent.getStringExtra(<span class="hljs-string">"StartedServiceTest"</span>);<span class="hljs-comment">//對于每一個啟動請求,都發送一個消息來啟動一個處理</span><span class="hljs-comment">//同時傳入啟動ID,以便任務完成后我們知道該終止哪一個請求。</span>Message message = startedServiceHandler.obtainMessage();message.arg1 = <span class="hljs-number">1</span>;startedServiceHandler.sendMessage(message);<span class="hljs-comment">//如果我們被殺死了,那從這里返回之后被重啟</span><span class="hljs-keyword">return</span> START_STICKY;}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDestroy</span>() {<span class="hljs-keyword">super</span>.onDestroy();Log.e(TAG, <span class="hljs-string">"onDestroy"</span>);}<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StartedServiceHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-title">StartedServiceHandler</span>(Looper looper) {<span class="hljs-keyword">super</span>(looper);}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) {<span class="hljs-comment">//通常我們在這里執行一些工作,比如下載文件。</span><span class="hljs-keyword">try</span> {Log.e(TAG, <span class="hljs-string">"開始在服務中處理信息"</span>);Thread.sleep(<span class="hljs-number">3000</span>);} <span class="hljs-keyword">catch</span> (InterruptedException e) {e.printStackTrace();}<span class="hljs-comment">//根據startId終止服務,這樣我們就不會在處理其它工作的過程中再來終止服務</span><span class="hljs-comment">//如果組件通過調用startService()(這會導致onStartCommand()的調用)啟動了服務,那么服務將一直保持運行,直至自行用stopSelf()終止或由其它組件調用stopService()來終止它。</span><span class="hljs-comment">//如果組件調用bindService()來創建服務(那onStartCommand()就不會被調用),則服務的生存期就與被綁定的組件一致。一旦所有客戶端都對服務解除了綁定,系統就會銷毀該服務。</span>stopSelf(msg.arg1);Log.e(TAG, <span class="hljs-string">"startedService處理數據完成后自動停止"</span>);}}<span class="hljs-comment">//不支持綁定,所以我們返回null</span><span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> IBinder <span class="hljs-title">onBind</span>(Intent intent) {<span class="hljs-comment">// TODO: Return the communication channel to the service.</span><span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;} }</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li></ul>

注意:我這里在StartedService中,使用了HandlerThread來實現在線程中處理事件。因為這里的服務還是在主線程中的,不能阻塞。

AndroidManifests.xml文件中注冊

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">service </span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"com.llay.admin.service.HelloStartedService"</span><span class="hljs-attribute">android:enabled</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:exported</span>=<span class="hljs-value">"true"</span> /></span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

運行圖:
打開服務:

關閉服務(完成后自動關閉):
在處理過程后,有這樣一句代碼,自動關閉。


關閉服務(手動關閉):
在按鈕點擊事件中,手動關閉。

4、1、1 IntentService代碼實現

注意:默認情況下,運行服務的進程與應用程序的相同,并且運行在應用程序的主線程中。
因此,如果你的服務要執行計算密集或阻塞的操作,而同時用戶又需要與同一個應用程序中的activity進行交互,那么服務將會降低activity的性能。
為了避免對應用程序性能的影響,你應該在服務中啟動一個新的線程。

IntentService:異步處理服務,新開一個線程:handlerThread在線程中發消息,然后接受處理完成后,會清理線程,并且關掉服務。
IntentService有以下特點:

(1) 它創建了一個獨立的工作線程來處理所有的通過onStartCommand()傳遞給服務的intents。

(2) 創建了一個工作隊列,來逐個發送intent給onHandleIntent()。

(3) 不需要主動調用stopSelft()來結束服務。因為,在所有的intent被處理完后,系統會自動關閉服務。

(4) 默認實現的onBind()返回null

(5) 默認實現的onStartCommand()的目的是將intent插入到工作隊列中

Activity中的方法代碼:

<code class="hljs java has-numbering"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initIntentService</span>() {<span class="hljs-comment">//Android5.0之后必須使用顯示intent來啟動</span><span class="hljs-comment">//Android的四大組件,只有BroadcastReceiver能夠動態在AndroidManifests文件中注冊</span><span class="hljs-keyword">final</span> Intent intent = <span class="hljs-keyword">new</span> Intent(<span class="hljs-string">"com.llay.admin.service.action.llay"</span>).setPackage(<span class="hljs-string">"com.llay.admin.mydemo"</span>);startedIntentService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(startedServiceTAG, <span class="hljs-string">"開啟Intent服務"</span>);intent.putExtra(<span class="hljs-string">"IntentServiceTest"</span>, <span class="hljs-string">"IntentServiceTest"</span>);startService(intent);}});stopIntentService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(stopServiceTAG, <span class="hljs-string">"手動Intent停止服務"</span>);stopService(intent);}});}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

HelloIntentService.java文件

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloIntentService</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">IntentService</span> {</span><span class="hljs-javadoc">/*** 構造方法是必需的,必須用工作線程名稱作為參數* 調用父類的[http://developer.android.com/reference/android/app/IntentService.html#IntentService(java.lang.String) IntentService(String)]構造方法。*/</span><span class="hljs-keyword">public</span> <span class="hljs-title">HelloIntentService</span>() {<span class="hljs-keyword">super</span>(<span class="hljs-string">"HelloIntentService"</span>);}<span class="hljs-javadoc">/*** IntentService從缺省的工作線程中調用本方法,并用啟動服務的intent作為參數。* 本方法返回后,IntentService將適時終止這個服務。*/</span><span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onHandleIntent</span>(Intent intent) {String s = intent.getStringExtra(<span class="hljs-string">"IntentServiceTest"</span>);Log.e(<span class="hljs-string">"IntentServiceTest"</span>, s);} }</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul>

AndroidManifests.xml文件中注冊

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">service </span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"com.llay.admin.service.HelloIntentService"</span><span class="hljs-attribute">android:enabled</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:exported</span>=<span class="hljs-value">"true"</span> /></span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

運行圖:
開啟Intent服務:

關閉Intent服務(這里和上面started服務一樣,可以自動關閉,可以手動關閉):

注意:這里我們來分析一下Service和IntentService的區別和使用地方。

<code class="hljs scss has-numbering">利用IntentService來實現一個started服務非常簡單。 不過,假如你的服務需要多線程運行(而不是通過一個工作隊列來處理啟動請求),那你可以擴展Service類來完成每個intent的處理。如你所見,它要干的事情比用IntentService時多了很多。不過,因為是自行處理每個<span class="hljs-function">onStartCommand()</span>調用,你可以同時處理多個請求。 本例中沒有這么去實現,但只要你愿意,你就可以為每個請求創建一個新的線程,并立即運行它們(而不是等待前一個請求處理完畢)。</code><ul class="pre-numbering" style=""><li>1</li></ul><ul class="pre-numbering" style=""><li>1</li></ul>

總結: 在當需要一起在線程(自己開)中處理,則使用Started服務。 在當需要一個一個在線程(自帶)中處理,則使用IntentService。

4、2 Bound服務的代碼實現

Activity中的方法代碼:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initBoundService</span>() {boundService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(boundServiceTAG, <span class="hljs-string">"綁定服務"</span>);<span class="hljs-comment">//綁定到LocalService</span>Intent intent = <span class="hljs-keyword">new</span> Intent(ServiceDemoActivity.<span class="hljs-keyword">this</span>, HelloBoundService.class);bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);Log.e(<span class="hljs-string">"BoundServiceTest"</span>, <span class="hljs-string">"BoundServiceStart"</span>);}});unboundService.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {Log.e(unBoundServiceTAG, <span class="hljs-string">"手動解除綁定"</span>);unbindService(serviceConnection);mBound = <span class="hljs-keyword">false</span>;}});showNumber.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {<span class="hljs-keyword">if</span> (mBound) {<span class="hljs-comment">//調用LocalService中的方法。</span><span class="hljs-comment">//不過,如果該調用會導致某些操作的掛起,那么調用應該放入單獨的線程中進行,</span><span class="hljs-comment">//以免降低activity的性能。</span><span class="hljs-keyword">int</span> num = helloBoundService.getRandomNumber();Toast.makeText(ServiceDemoActivity.<span class="hljs-keyword">this</span>, <span class="hljs-string">"number: "</span> + num, Toast.LENGTH_SHORT).show();}}});serviceConnection = <span class="hljs-keyword">new</span> ServiceConnection() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onServiceConnected</span>(ComponentName name, IBinder service) {<span class="hljs-comment">//我們已經綁定到LocalService了,對IBinder進行類型轉換(cast)并獲得LocalService對象的實例</span>HelloBoundService.LocalBinder localBinder = (HelloBoundService.LocalBinder) service;helloBoundService = localBinder.getHelloBoundService();mBound = <span class="hljs-keyword">true</span>;}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onServiceDisconnected</span>(ComponentName name) {mBound = <span class="hljs-keyword">false</span>;}};}<span class="hljs-comment">//以下是綁定服務的一些回調函數</span><span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() {<span class="hljs-keyword">super</span>.onStart();}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStop</span>() {<span class="hljs-keyword">super</span>.onStop();<span class="hljs-comment">//與服務解除綁定</span><span class="hljs-keyword">if</span> (mBound) {unbindService(serviceConnection);mBound = <span class="hljs-keyword">false</span>;}Log.e(unBoundServiceTAG, <span class="hljs-string">"自動解除綁定"</span>);}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li></ul>

HelloBoundService.java文件:

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloBoundService</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Service</span> {</span><span class="hljs-comment">//給客戶端的Binder</span><span class="hljs-keyword">public</span> IBinder mBinder = <span class="hljs-keyword">new</span> LocalBinder();<span class="hljs-comment">//生成隨機數</span><span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Random mGenerator = <span class="hljs-keyword">new</span> Random();<span class="hljs-javadoc">/*** 用于客戶端Binder的類。* 因為知道本服務總是運行于與客戶端相同的進程中,我們就不需要用IPC進行處理。*/</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocalBinder</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Binder</span> {</span><span class="hljs-keyword">public</span> HelloBoundService <span class="hljs-title">getHelloBoundService</span>() {<span class="hljs-keyword">return</span> HelloBoundService.<span class="hljs-keyword">this</span>;}}<span class="hljs-annotation">@Nullable</span><span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> IBinder <span class="hljs-title">onBind</span>(Intent intent) {<span class="hljs-keyword">return</span> mBinder;}<span class="hljs-javadoc">/*** method for clients*/</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getRandomNumber</span>() {<span class="hljs-keyword">return</span> mGenerator.nextInt(<span class="hljs-number">100</span>);} }</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li></ul>

注意:如果你的服務只用于本地應用程序并且不需要跨進程工作,那你只要實現自己的 Binder
類即可,這樣你的客戶端就能直接訪問服務中的公共方法了。
注意:僅當客戶端和服務位于同一個應用程序和進程中,這也是最常見的情況,這種方式才會有用。比如,一個音樂應用需要把一個activity綁定到它自己的后臺音樂播放服務上,采用這種方式就會很不錯。
以下是設置步驟: 1、在你的服務中,創建一個Binder的實例,其中實現以下三者之一:

  • 包含了可供客戶端調用的公共方法
  • 返回當前Service實例,其中包含了可供客戶端調用的公共方法。
  • 或者,返回內含服務類的其它類的一個實例,服務中包含了可供客戶端調用的公共方法。

2、從回調方法onBind()中返回Binder的該實例。
3、在客戶端中,在回調方法onServiceConnected()中接收Binder并用所提供的方法對綁定的服務進行調用。 注意:
服務和客戶端之所以必須位于同一個應用程序中,是為了讓客戶端能夠正確轉換(cast)返回的對象并調用對象的API。
服務和客戶端也必須位于同一個進程中,因為這種方式不能執行任何跨進程的序列化(marshalling)操作。

AndroidManifests.xml文件中注冊

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">service </span> <span class="hljs-attribute">android:name</span>=<span class="hljs-value">"com.llay.admin.service.HelloBoundService"</span><span class="hljs-attribute">android:enabled</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:exported</span>=<span class="hljs-value">"true"</span> /></span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

運行圖:
綁定服務:

解絆服務:

五、擴展

創建一個支持綁定的服務時,你必須提供一個 IBinder ,用作客戶端和服務間進行通信的編程接口。定義這類接口的方式有三種:

擴展Binder類
如果服務是你的應用程序所私有的,并且與客戶端運行于同一個進程中(通常都是如此),你應該通過擴展Binder類來創建你的接口,并從onBind()返回一個它的實例。客戶端接收該Binder對象并用它來直接訪問Binder甚至Service中可用的公共(public)方法。
如果你的服務只是為你自己的應用程序執行一些后臺工作,那這就是首選的技術方案。不用這種方式來創建接口的理由只有一個,就是服務要被其它應用程序使用或者要跨多個進程使用。

使用Messenger
如果你需要接口跨越多個進程進行工作,可以通過Messenger來為服務創建接口。在這種方式下,服務定義一個響應各類消息對象Message的Handler。此Handler是Messenger與客戶端共享同一個IBinder的基礎,它使得客戶端可以用消息對象Message向服務發送指令。此外,客戶端還可以定義自己的Message,以便服務能夠往回發送消息。
這是執行進程間通信(IPC)最為簡便的方式,因為Messenger會把所有的請求放入一個獨立進程中的隊列,這樣你就不一定非要把服務設計為線程安全的模式了。

使用AIDL
Android接口定義語言AIDL(Android Interface Definition Language)完成以下的所有工作:將對象解析為操作系統可識別的原始形態,并將它們跨進程序列化(marshal)以完成IPC。前一個使用Messenger的方式,實際上也是基于AIDL的,它用AIDL作為底層結構。如上所述,Messenger將在一個單獨的進程中創建一個包含了所有客戶端請求的隊列,這樣服務每次就只會收到一個請求。可是,如果想讓你的服務能同時處理多個請求,那你就可以直接使用AIDL。這種情況下,你的服務必須擁有多線程處理能力,并且是以線程安全的方式編寫的。
要直接使用AIDL,你必須創建一個.aidl文件,其中定義了編程的接口。Android SDK工具使用此文件來生成一個抽象類(abstract class),其中實現了接口及對IPC的處理,然后你就可以在自己的服務中擴展該類。

注意:

絕大多數應用程序都不應該用AIDL來創建bound服務,因為這可能需要多線程處理能力并且會讓代碼變得更為復雜。
因此,AIDL對絕大多數應用程序都不適用,并且本文也不會討論如何在服務中使用它的內容。如果你確信需要直接使用AIDL,那請參閱 AIDL
文檔。

總結

以上是生活随笔為你收集整理的Service的理解和使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。