一、服務的生命周期
服務與活動一樣,在它的整個生命周期中存在着一些事件,下圖可以很好解釋整個過程以及涉及到的方法:
在真實的使用中,Service來還包含一個OnBind方法,並且必須要使用該方法,但是只要返回NULL即可,除非當前服務是一個綁定服務,那么就要返回實現了IBinder的實例。
二、回調方法的總結
上圖中涉及到了幾個方法,下面將做簡單的介紹:
OnCreate:只會在服務第一次開啟的時候調用,主要負責一些初始化代碼
OnStartCommand:每次啟動服務都會調用該方法,可能來自StartService或者由系統重啟。一般負責開啟需要長時間的任務。並且該方法還要返回StartCommandResult類型的枚舉,該返回值將影響系統重啟該服務的細節。
OnDestroy:當服務使用StopSelf或者StopService時調用,主要用來釋放資源等。
三、返回不同StartCommandResult服務的區別
Sticky:當服務由於內存不夠被系統關閉后,將會由系統重啟該服務,但是傳入OnStartCommand方法的intent參數為NULL,意味着該類型的服務無法恢復上次的狀態,只能進行常規的長時間任務。
RedeliverIntent:該類型的服務與Sticky的唯一的區別就是在系統重啟該服務時,將會將上次關閉的服務的狀態傳遞給OnStartCommand方法,用來恢復上次的任務繼續執行。適合需要長時間連續的任務。
NotSticky:該服務被系統關閉后將不會重啟。
StickyCompatibility:在API 5或以上的環境中的行為與Sticky一樣,相反在API 5以下可能不會重啟服務。
四、實現一個服務
這里我們需要繼承自Service並還要需要加上Service注解屬性(項目自行新建)
1 namespace ServiceStudy 2 { 3 [Service] 4 public class MainService : Service 5 { 6 7 } 8 }
其中[Service]負責在AndroidManifest.xml注冊服務,比如上面的服務將會生成如下字符串:
1 <service android:name="ServiceStudy.MainService"></service>
下面我們開始具體實現一個服務,上面已經說明了無論任何服務都要重寫OnBind方法,所以我們先重寫該方法:
1 public override Android.OS.IBinder OnBind(Android.Content.Intent intent) 2 { 3 return null; 4 }
然后是OnCreate方法:
1 public override void OnCreate() 2 { 3 base.OnCreate(); 4 Log.Debug("xamarin", "創建服務"); 5 }
接着是OnStartCommand方法:
1 public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) 2 { 3 Log.Debug("xamarin", "啟動服務"); 4 return StartCommandResult.Sticky; 5 }
最后就是OnDestroy方法:
1 public override void OnDestroy() 2 { 3 base.OnDestroy(); 4 Log.Debug("xamarin", "關閉服務"); 5 }
這樣一個簡單的服務就完成了,下面是整體代碼:

1 [Service] 2 public class MainService : Service 3 { 4 public override void OnCreate() 5 { 6 base.OnCreate(); 7 Log.Debug("xamarin", "創建服務"); 8 } 9 10 public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) 11 { 12 Log.Debug("xamarin", "啟動服務"); 13 return StartCommandResult.Sticky; 14 } 15 16 public override void OnDestroy() 17 { 18 base.OnDestroy(); 19 Log.Debug("xamarin", "關閉服務"); 20 } 21 22 public override Android.OS.IBinder OnBind(Android.Content.Intent intent) 23 { 24 return null; 25 } 26 }
五、啟用與停止服務
有了上面的服務我們現在就可以開啟它了,開啟服務的方法如下:
1 StartService(new Intent(this, typeof(MainService)));
停止服務的方法如下:
1 StopService(new Intent(this, typeof(MainService)));
首先打開Main.axml,再拖拽一個按鈕進去,並設置他們的Text,以及id為@+id/startButton和@+id/stopButton,結果如下:
接着打開MainActivity.cs文件,為這兩個按鈕綁定監聽事件:

1 public class MainActivity : Activity 2 { 3 protected override void OnCreate(Bundle bundle) 4 { 5 base.OnCreate(bundle); 6 SetContentView(Resource.Layout.Main); 7 Button startButton = FindViewById<Button>(Resource.Id.startButton); 8 Button stopButton = FindViewById<Button>(Resource.Id.stopButton); 9 10 startButton.Click += delegate 11 { 12 StartService(new Intent(this, typeof(MainService))); 13 }; 14 15 stopButton.Click += delegate 16 { 17 StopService(new Intent(this, typeof(MainService))); 18 }; 19 } 20 }
最終在模擬機上進行測試,得出下面的結果:
從中可以看到多個連續的啟動服務,因為筆者按下了返回退出了應用,然后再返回到應用中,開啟服務,那么就只顯示啟動服務了,而不會經過創建服務了。
六、使用startId關閉服務
通過上面的例子,大家一定有人不停的開啟服務。當然每次開啟的都是一個新的服務。但是關閉服務的時候並不是關閉其中一個,而是把所有的服務都關閉了。由這個就需要考慮一種情況,就是如何區分不同的實例以及關閉不同的實例呢?
大家可以看看
服務中已經提供了專門的方法,當然如果是關閉當前的服務可以直接用StopSelf(),下面我們將OnStartCommand中重寫,開啟一個線程:

1 public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) 2 { 3 Log.Debug("xamarin", "啟動服務"); 4 new Thread(() => 5 { 6 Log.Debug("xamarin", startId + "號服務的線程啟動"); 7 Thread.Sleep(1000); 8 Log.Debug("xamarin", startId + "號服務的線程關閉"); 9 StopSelf(startId); 10 }).Start(); 11 return StartCommandResult.Sticky; 12 }
我們這里使用了StopSelft的重載版本關閉了服務。
然后我們再開始進行調試,首先我們按下一次開啟服務,將出現如下的結果:
接着我們快速的點擊兩次開啟服務,將出現如下的結果:
通過這張圖我們可以看到,輸出了1號和2號,同時在完成執行后,我們再點關閉服務就沒有任何反應了,因為服務自己已經把自己關閉了。
七、通過Intent Filter開啟服務
上面所有的服務開啟方法都是通過類型開啟的,但是這樣的缺點顯而易見,如果我們改變了服務的名稱就需要改正其他的地方,而通過這節我們將可以使用字符串名稱來開啟服務。
這里我們需要使用IntentFilter注解屬性,比如下面這樣的注解屬性:
則會在AndroidManifest.xml中生成如下的字符串:
1 <service android:name="ServiceStudy. MainService"> 2 <intent-filter> 3 <action android:name="xamarin-cn.com.mainservice" /> 4 </intent-filter> 5 </service>
我們先給MainService加上Intent Filter:
1 [Service] 2 [IntentFilter(new string[]{"xamarin-cn.com.mainservice"})] 3 public class MainService : Service
然后修改開啟服務地方的代碼:

1 protected override void OnCreate(Bundle bundle) 2 { 3 base.OnCreate(bundle); 4 SetContentView(Resource.Layout.Main); 5 Button startButton = FindViewById<Button>(Resource.Id.startButton); 6 Button stopButton = FindViewById<Button>(Resource.Id.stopButton); 7 8 startButton.Click += delegate 9 { 10 StartService(new Intent("xamarin-cn.com.mainservice")); 11 }; 12 13 stopButton.Click += delegate 14 { 15 StopService(new Intent("xamarin-cn.com.mainservice")); 16 }; 17 }
這里我們依然還是使用Intent但是傳遞的參數已經變成了字符串。