在上節中我記錄了Service的生命周期,現在就來熟悉一下如何來使用Service和Service有哪些特別需要注意的知識點。
基本流程:
一、建立Service,通過編寫子類繼承Service或IntentService。
二、在AndroidManifest.xml中注冊<service/>。
三、在別的組件中調用startService(Intent intent)。
具體說明:
第一步:建立服務
-extends Service
子類Service必須要覆寫的回調方法是onBind(Intent intent),其返回IBinder對象。如果不需要提供綁定服務直接返回null,之后在生命周期方法中處理工作。其特點是用程序的主線程,如果直接做耗時處理的話會影響程序的性能,導致程序UI線程阻塞。如在onStartCommand()中執行如下代碼,讓線程等待5秒,將導致主線程阻塞,界面在線程等待期間,不能作任何響應。
long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } Log.v(TAG, "工作線程醒過來了!"); } }
正確的寫法是為Service新開線程進行耗時處理,如下:
package com.example.test; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; import android.util.Log; /** * 服務開啟工作線程模擬耗時工作5秒 * @author Change * */ public class MainService extends Service { public static final String TAG = "show"; private Looper looper = null; private MyHandler handler = null; public class MyHandler extends Handler{ public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.v(TAG, "工作線程睡覺中!"); long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } //執行完,停止服務! stopSelf(msg.arg1); Log.v(TAG, "工作線程醒過來了!"); } } } } @Override public void onCreate() { super.onCreate(); //創建handler專用后台線程。 HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); //創建線程對應handler looper = thread.getLooper(); handler = new MyHandler(looper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Message msg = handler.obtainMessage(); msg.arg1 = startId; handler.sendMessage(msg); //如果被系統關閉將自動重啟 return START_STICKY; } @Override public IBinder onBind(Intent arg0) { // 不需要提供服務綁定的時候返回null。 return null; } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "服務已完成任務中止了!"); } }
程序執行結果:
-extends IntentService
上面通過繼承Service基類實現子類的工作服務,如果當你的服務不需要操作多個任務時有更簡單的方式就是通過繼承IntentService,是一個默認有后台線程的服務,只需要重寫構造,調用父類構造,傳入准備創建的后台線程名稱:
package com.example.test; import android.app.IntentService; import android.content.Intent; import android.util.Log; /** * 簡單后台線程服務 * @author Change * */ public class BackgroundService extends IntentService { public static final String TAG = "show"; //必須實現該構造 public BackgroundService() { //創建一個名為BackgroundService的后台工作線程。 super("BackgroundService"); } //該方法中執行后台操作 @Override protected void onHandleIntent(Intent i) { Log.v(TAG, "工作線程睡覺中!"); long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } Log.v(TAG, "工作線程醒過來了!"); } } } }
執行結果跟extends Service一樣。
第二步:注冊服務
在AndroidManifest.xml中注冊剛剛創建的服務。
在application內添加
<service android:name=".MainService" android:exported="false"> <intent-filter > <action .../> <category .../> <data .../> </intent-filter> </service>
最簡單的注冊方式只需要提供一個名稱:<service android:name=".MainService"/>
exported是否為其他程序提供服務。為true的話可以給其它程序綁定使用,為false的話則不行。
Service跟Activity一樣,同樣可以注冊intent-filter內的相關內容。
第三步:啟動服務
服務不能自己啟動,要通過其他組件來啟動。可以是Activity、Service、BroadcastReceiver等。通過調用startService()即可。
Intent start = new Intent(this,BackgroundService.class); startService(start);
或者用adb命令啟動
其它參數
這個在做與pc進行adb通信時會用到。