Android建立服務之started service

來源:互聯網
上載者:User

建立started service
應用組件(例如Activity)調用startService()來啟動一個Service,將需要的參數通過Intent傳給Service,Service將會在onStartCommand函數中獲得Intent。
有兩種方式可以建立started service,一種是擴充Service類,另外一種是擴充IntentService類

擴充Service 這是所有服務的基類。擴充這個類的時候,特別重要的一點是,需要建立一個新的線程來做服務任務,因為service預設是運行在你的主線程(UI線程)中的,它會使你的主線程運行緩慢。
擴充IntentService 這是一個service的子類,他可以在一個背景工作執行緒中處理所有的啟動請求。如果你不需要同一時刻出來所有的服務要求,使用IntentService是一個很好的選擇。你需要做的僅僅是實現onHandlerIntent()方法,通過這個函數處理接受的每一個啟動請求。


下面我們學習如何擴充IntentService類和Service類
擴充IntentService類
IntentService做了什嗎?
1.建立一個獨立於主線程的背景工作執行緒,用於執行通過onStartCommand()傳來的所有的intent。2.建立一個工作隊列,將接受的所有intent一個一個的傳給onHandlerIntent(),所以同一時間內你只處理一個intent,不用擔心多線程的問題。3.當所有的請求都處理完後,停止服務,所以你不需要手動調用stopSelf()。4.提供onBind()函數的預設實現,返回null5.提供onStartCommand()函數的預設實現,它把intent發送到工作隊列中去,然後工作隊列再發送到你的onHandlerIntent()函數中。

有了上面的基礎,你僅僅要做的就是實現onHandlerIntent()。並且實現一個小小的建構函式。
參考下面的例子:
public class HelloIntentService extends IntentService {

/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}

/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}

如果你要實現其他的回呼函數,例如 onCreate , onStartCommand ,onDestroy 一定記得調用父類相應的函數,這樣IntentService才能正確的處理背景工作執行緒。
例如,你需要在onStartCommand函數中彈出一個提示,那麼你可以這樣寫:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}
有一點例外的是,如果你需要其他組件綁定服務,那麼你的onBind函數不需要調用父類的onBind。
在下一節中,你將會看到通過擴充service類來實現與本節相同的服務,所不同的是代碼會更多,但是同樣意味著更靈活,特別是你需要同時處理多個請求時,比較適合直接擴充Service。
擴充Service類
如同你在上一節看到的一樣,使用IntentService來實現一個started service非常簡單。如果你需要你的service來執行多個線程,那麼你需要擴充Service類去處理每個intent。
作為對比,下面的例子用Service類實現了和上一節中一樣功能的服務。
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}

@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);

// If we get killed, after returning from here, restart
return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}

@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
如同你看到的,比IntentService的例子多了好多代碼。
因為你自己處理每次的onStartcommand(),所以你可以在同一時間處理多個請求。這個例子沒有這樣做,但是如果你願意,你完全可以每收到一個請求的時候,建立一個新線程並且立即運行,而不是等到上一個請求處理完成後再運行。
注意,onStartCommand()函數必須返回一個整數。這個整數描述了當系統殺死該服務時將要如何處理該服務。返回值必須是下面幾個值:
START_NOT_STICKY 在onStartCommand()返回後,系統殺死服務,服務將不會重啟,除非有pending intents(目前筆者還不懂什麼是pending Intents)要投遞。這比較適合非常容易就可以重新啟動未完成任務的情況。
START_STICKY 在系統殺死服務後,重啟服務並且調用onStartCommand(),但是不重新投遞上一次的intent。系統會傳給onStartCommand()函數null,除非有pending intent來啟動服務,會傳給onStartCommand()相應的intent。這種做法比較適合媒體播放服務,不需要執行命令,但是獨立運行,常處於等待任務的服務。
START_REDELIVER_INTENT 在系統殺死服務後,重啟服務並且調用onStartCommand(),參數傳入上一次的intent,然後接下來是pending intent傳入onStartCommand()。這比較適合於正在執行一項工作,它不能被立刻恢複,例如下載檔案。

啟動Service
你可以從一個Activity或者其他組件調用startService(intent)來啟動服務。Android系統會調用服務的onStartCommand()函數並且傳給它intent。
用上一節的HelloService來做個例子:
Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService()會立刻返回,Android系統會調用服務的onStartCommand()函數。如果這是服務沒有在運行,系統會首先調用onCreate()函數,然後會緊接著調用onStartCommand()函數。
如果服務沒有提供綁定,那麼通過startService()函數傳入的intent就是應用組件和服務進行互動的唯一途徑。如果你想服務發送結果給客戶組件,那麼客戶組件需要在啟動服務時,建立一個用於廣播的PendingIntent,通過intent投遞給服務。這樣,服務就可以利用廣播把結果發送給客戶組件。
多個請求會導致服務的onStartCommand()被調用多次。但是,只需要一個停止請求(stopSelf() 或 stopService())就會使服務停止。
停止服務
一個啟動的服務必須管理自己的生命週期。因為除非系統需要回收資源的時候,系統不會停止或者銷毀服務。所以,服務必須通過調用stopSelf()來停止自己,或者有其他組件調用stopService()。
一擔收到stopSelf()或stopService()的停止請求,系統會立刻銷毀服務。
如果你的服務同時處理多個服務要求,當某個請求完成時就不能馬上停止服務,因為你可能已經又接受了一個新的請求(在第一個請求完成時結束服務會終止第二個請求)。為瞭解決這個問題,你可以調用stopSelf(int)函數來保證你的停止請求總是基於最近的一次服務要求。這是因為,調用stopSelf(int)函數會把onStartCommand()函數傳入的startId傳給停止請求。當你的startId和最近一次接受的服務要求不匹配時,服務不會結束。
注意:stopSelf(int)函數只是簡單的與最近一次收到的startId比較,如果你的服務處理過程是多線程的,可能後收到的服務要求先完成,那stopSelf(int)的方案不適合你,你應該手動管理接受到的服務要求和完成的服務,比如在onStartCommand()函數中把startId記錄到一個表中,在完成服務任務時在表中記錄完成狀態,在確保表中任務都完成的情況下直接調用stopSelf()來停止服務。
在前台運行服務
一個前台服務是使用者能夠很明顯意識到的服務,當可用記憶體比較低的時候,系統不會殺掉前台服務。一個前台服務必須提供一個狀態列通知,放在正在運行條目裡,這意味著只要服務沒有停止或者一直是前台服務,這個通知就不會被消失。
舉個例子,一個音樂播放器服務應該被設定為前台運行,因為使用者非常明顯知道他在運行。這個狀態列通知可以顯示現正播放的歌曲,並且可以允許使用者點擊進入音樂播放介面。
要使服務運行在前台只要調用startForeground()。這個方法有兩個參數:一個通知的整數ID和一個狀態列通知。程式碼片段:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

使用stopForeground()函數可以把服務從前台移除。這個函數帶一個布爾值參數,來表示是否從狀態列移除通知。這個函數不會使服務停止。如果把前台服務停止掉,那麼通知也會同時被移除。
參考:http://developer.android.com/guide/components/services.html#CreatingStartedService轉載請註明出處:Android建立服務之started servicehttp://blog.csdn.net/oracleot/article/details/18817087



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.