標籤:
Service作為Android中四大基本組件之一,也是App中經常要用到的。其實,Service這塊的知識點還是有些多的,下面要分別一一總結下。
Service通常總是稱之為“後台服務”,其中“後台”一詞是相對於前台而言的,具體是指其本身的運行並不依賴於使用者可視的UI介面,因此,從實際業務需求上來理解,Service的適用情境應該具備以下條件:
1.並不依賴於使用者可視的UI介面(當然,這一條其實也不是絕對的,如前台Service就是與Notification介面結合使用的);
2.具有較長時間的運行特性。
1.Service AndroidManifest.xml 聲明
一般而言,從Service的啟動方式上,可以將Service分為Started Service和Bound Service。無論哪種具體的Service啟動類型,都是通過繼承Service基類自訂而來。在使用Service時,要想系統能夠找到此自訂Service,無論哪種類型,都需要在AndroidManifest.xml中聲明,文法格式如下:
1 <service android:enabled=["true" | "false"] 2 android:exported=["true" | "false"] 3 android:icon="drawable resource" 4 android:isolatedProcess=["true" | "false"] 5 android:label="string resource" 6 android:name="string" 7 android:permission="string" 8 android:process="string" > 9 . . .10 </service>
其中,android:exported屬性上一篇博文中對此已進行詳盡描述,android:name對應Service類名,android:permission是許可權聲明,android:process設定具體的進程名稱。需要注意的是Service能否單獨使用一個進程與其啟動方式有關,本後下面會給出具體說明。其他的屬性此處與其他組件基本相同,不再過多描述。
註:如果自訂Service沒有在AndroidManifest.xml中聲明,當具體使用時,不會像Activity那樣直接崩潰報錯,但是Service沒法啟動,這反而使得有時候不容易發現忘了聲明而一時定位不到問題。
2.Started Service
Started Service相對比較簡單,通過context.startService(Intent serviceIntent)啟動Service,context.stopService(Intent serviceIntent)停止此Service。當然,在Service內部,也可以通過stopSelf(...)方式停止其本身。
1)Started Service自訂
下面程式碼片段顯示的是一個最基本的Started Service的自訂方式:
1 public class MyService extends Service { 2 3 public static final String TAG = "MyService"; 4 5 @Override 6 public IBinder onBind(Intent intent) { 7 return null; 8 } 9 10 @Override11 public void onCreate() {12 super.onCreate();13 Log.w(TAG, "in onCreate");14 }15 16 @Override17 public int onStartCommand(Intent intent, int flags, int startId) {18 Log.w(TAG, "in onStartCommand");19 Log.w(TAG, "MyService:" + this);20 String name = intent.getStringExtra("name");21 Log.w(TAG, "name:" + name);22 return START_STICKY;23 }24 25 @Override26 public void onDestroy() {27 super.onDestroy();28 Log.w(TAG, "in onDestroy");29 }30 }
其中,onBind(...)函數是Service基類中的唯一抽象方法,子類都必須重寫實現,此函數的傳回值是針對Bound Service類型的Service才有用的,在Started Service類型中,此函數直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相應生命週期階段的回呼函數。
2) Started Service使用
1 public class MainActivity extends Activity { 2 3 public static final String TAG = "MainActivity"; 4 5 private Button startServiceBtn; 6 private Button stopServideBtn; 7 private Button goBtn; 8 9 private Intent serviceIntent;10 11 @Override12 protected void onCreate(Bundle savedInstanceState) {13 super.onCreate(savedInstanceState);14 setContentView(R.layout.activity_main);15 16 startServiceBtn = (Button) findViewById(R.id.start_service);17 stopServideBtn = (Button) findViewById(R.id.stop_service);18 goBtn = (Button) findViewById(R.id.go);19 20 startServiceBtn.setOnClickListener(new View.OnClickListener() {21 @Override22 public void onClick(View v) {23 serviceIntent = new Intent(MainActivity.this, MyService.class);24 startService(serviceIntent);25 }26 });27 28 stopServideBtn.setOnClickListener(new View.OnClickListener() {29 @Override30 public void onClick(View v) {31 stopService(serviceIntent);32 }33 });34 35 goBtn.setOnClickListener(new View.OnClickListener() {36 @Override37 public void onClick(View v) {38 Intent intent = new Intent(MainActivity.this, BActivity.class);39 startActivity(intent);40 }41 });42 43 }44 45 @Override46 protected void onDestroy() {47 super.onDestroy();48 Log.w(TAG, "in onDestroy");49 }50 }
如上程式碼片段,
當Client調用startService(Intent serviceIntent)後,如果MyService是第一次啟動,首先會執行 onCreate()回調,然後再執行onStartCommand(Intent intent, int flags, int startId),當Client再次調用startService(Intent serviceIntent),將只執行onStartCommand(Intent intent, int flags, int startId),因為此時Service已經建立了,無需執行onCreate()回調。無論多少次的startService,只需要一次stopService()即可將此Service終止,執行onDestroy()函數(其實很好理解,因為onDestroy()與onCreate()回調是相對的)。
下面重點關注下onStartCommand(Intent intent, int flags, int startId)方法。
其中參數flags預設情況下是0,對應的常量名為START_STICKY_COMPATIBILITY。startId是一個唯一的整型,用於表示此次Client執行startService(...)的請求請求標識,在多次startService(...)的情況下,呈現0,1,2....遞增。另外,此函數具有一個int型的傳回值,具體的可選值及含義如下:
START_NOT_STICKY:當Service因為記憶體不足而被系統kill後,接下來未來的某個時間內,即使系統記憶體足夠可用,系統也不會嘗試重新建立此Service。除非程式中Client明確再次調用startService(...)啟動此Service。
START_STICKY:當Service因為記憶體不足而被系統kill後,接下來未來的某個時間內,當系統記憶體足夠可用的情況下,系統將會嘗試重新建立此Service,一旦建立成功後將回調onStartCommand(...)方法,但其中的Intent將是null,pendingintent除外。
START_REDELIVER_INTENT:與START_STICKY唯一不同的是,回調onStartCommand(...)方法時,其中的Intent將是非空,將是最後一次調用startService(...)中的intent。
START_STICKY_COMPATIBILITY:compatibility version of {@link #START_STICKY} that does not guarantee that {@link #onStartCommand} will be called again after being killed。此值一般不會使用,所以注意前面三種情形就好。
以上的描述中,”當Service因為記憶體不足而被系統kill後“一定要非常注意,因為此函數的傳回值設定只是針對此種情況才有意義的,換言之,當認為的kill掉Service進程,此函數傳回值無論怎麼設定,接下來未來的某個時間內,即使系統記憶體足夠可用,Service也不會重啟。
Android總結篇系列:Android Service