無論是何種Service,它默認都是在應用程序的主線程(亦即UI線程)中運行的。因此,若是你的Service將要運行很是耗時或者可能被阻塞的操做時,你的應用程序將會被掛起,甚至會出現ANR錯誤。爲了不這一問題,你應該在Service中從新啓動一個新的線程來進行這些操做。現有兩種方法共你們參考:html
① 直接在Service的onStartCommand()方法中重啓一個線程來執行,如:java
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- MyServiceActivity.updateLog(TAG + " ----> onStartCommand()");
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 此處進行耗時的操做,這裏只是簡單地讓線程睡眠了1s
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
- return START_STICKY;
- }
② Android SDK 中爲咱們提供了一個現成的Service類來實現這個功能,它就是IntentService,它主要負責如下幾個方面:android
onStartCommand()
separate from your application's main thread.生成一個默認的且與主線程互相獨立的工做者線程來執行全部傳送至 onStartCommand() 方法的Intetnt多線程
onHandleIntent()
implementation, so you never have to worry about multi-threading.生成一個工做隊列來傳送Intent對象給你的onHandleIntent()方法,同一時刻只傳送一個Intent對象,這樣一來,你就沒必要擔憂多線程的問題。併發
stopSelf()
.在全部的請求(Intent)都被執行完之後會自動中止服務,因此,你不須要本身去調用stopSelf()方法來中止該服務app
onBind()
that returns null.提供了一個onBind()方法的默認實現,它返回nullide
onStartCommand()
that sends the intent to the work queue and then to your onHandleIntent()
implementation提供了一個onStartCommand()方法的默認實現,它將Intent先傳送至工做隊列,而後從工做隊列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent對相應的處理函數
以上,英文來自官方SDK,中文爲我所譯。this
從以上看來,你所須要作的就是實現 onHandleIntent() 方法,在該方法內實現你想進行的操做。另外,繼承IntentService時,你必須提供一個無參構造函數,且在該構造函數內,你須要調用父類的構造函數,以下:spa
- public HelloIntentService() {
- super("HelloIntentService");
- }
下面給出一例,來解釋一下:
- // activity 的onCreate()
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- startSer1 = (Button) findViewById(R.id.startSer1);
- stopSer1 = (Button) findViewById(R.id.stopSer1);
- startSer2 = (Button) findViewById(R.id.startSer2);
- stopSer2 = (Button) findViewById(R.id.stopSer2);
- log = (TextView) findViewById(R.id.log);
- logView = (ScrollView) findViewById(R.id.logView);
- startSer1.setOnClickListener(btnListener);
- stopSer1.setOnClickListener(btnListener);
- startSer2.setOnClickListener(btnListener);
- stopSer2.setOnClickListener(btnListener);
- intent = new Intent(MyServiceActivity.this, IntentServiceDemo.class);
- // 打印出主線程的ID
- long id = Thread.currentThread().getId();
- updateLog(TAG + " ----> onCreate() in thread id: " + id);
- }
- // service 代碼
- package com.archer.rainbow;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import android.app.IntentService;
- import android.content.Intent;
- public class IntentServiceDemo extends IntentService {
- private static final String TAG = "IntentServiceDemo";
- private static final SimpleDateFormat SDF_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS");
- public IntentServiceDemo() {
- super(TAG);
- MyServiceActivity.updateLog(TAG + " ----> constructor");
- }
- @Override
- public void onCreate() {
- super.onCreate();
- // 打印出該Service所在線程的ID
- long id = Thread.currentThread().getId();
- MyServiceActivity.updateLog(TAG + " ----> onCreate() in thread id: "
- + id);
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- MyServiceActivity.updateLog(TAG + " ----> onDestroy()");
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- MyServiceActivity.updateLog(TAG + " ----> onStartCommand()");
- // 記錄發送此請求的時間
- intent.putExtra("time", System.currentTimeMillis());
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void setIntentRedelivery(boolean enabled) {
- MyServiceActivity.updateLog(TAG + " ----> setIntentRedelivery()");
- super.setIntentRedelivery(enabled);
- }
- @Override
- protected void onHandleIntent(Intent intent) {
- // 打印出處理intent所用的線程的ID
- long id = Thread.currentThread().getId();
- MyServiceActivity.updateLog(TAG
- + " ----> onHandleIntent() in thread id: " + id);
- long time = intent.getLongExtra("time", 0);
- Date date = new Date(time);
- try {
- // 打印出每一個請求對應的觸發時間
- MyServiceActivity.updateLog(TAG
- + " ----> onHandleIntent(): 下載文件中..." + SDF_DATE_FORMAT.format(date));
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
應用啓動時,界面以下:
今後圖能夠看出,主線程(UI線程)的ID是1。接,連續點擊三次Start Service 1 按鈕,得以下畫面:
今後圖中能夠看出,IntentServiceDemo的onCreate()所處的線程ID仍爲1,說明它是在主線程中被執行的,且只被執行一次。而後,我每點擊一次按鈕,它都會觸發一下onStartCommand()方法。仔細看第二次與第三次的onCommand()方法以及onHandleIntent()打印出來的語句,你會發現,第2、三兩次點擊按鈕與第一次點擊按鈕的時間是沒有超過3秒鐘的,它們是連續被執行的,這說明了什麼呢?說明,在第一個intent被處理時(即onHandleIntent()處於運行中),該Service仍然能夠接受新的請求,但接受到新的請求後並無當即執行,而是將它們放入了工做隊列中,等待被執行。
這就是 IntentService 的簡單用法。但你如果想在Service中讓多個線程併發的話,就得另想法子嘍。好比,使用第一種方法,在Service內部起多個線程,可是這樣的話,你可要處理好線程的同步哦~~~