android Service完全解析,androidservice
老規矩,先看官方文檔是怎麼說的。
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
以我的理解呢,大概就是說:
service是一個沒有使用者介面並且運行在後台以執行長時間耗時操作的app application組件。其它的application 組件能夠啟動service,而且service將一直執行下去,即使使用者從當前service所屬的application切換到了其它的application。另外,一個組件可以綁定到一個服務來和它互動,甚至是處理序間通訊(IPC機制)。for example,一個服務可能會處理網路操作,播放音樂,處理檔案的IO操作,或者與content provider互動,所有的操作都是在後台完成的。
A service can essentially take two forms:
1.startedA service is "started" when an application component (such as an activity) startsit by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. For example, it might download or upload a file over the network. When the operation is done, the service should stop itself.2.BoundA service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
1.started
當一個application 組件通過調用start Service()啟動service之後service處於“started”形式。一旦service啟動,它將在無限的後台運行,即使觸發service的組件已經被銷毀。通常,一個started的形式的service執行單一操作,並且不返回結果給啟動它的組件。for example,它可能從網路下載或者上傳檔案。當操作結束後,service應該結束掉它自己。
2.Bound
當一個application組件通過調用bindService()使一個service處於“bound”形式。一個bound的service提供了一個C/S介面以完成application 組件和這個service的互動,send requests,getresults,甚至通過跨進成調度來通訊。一個bound service只有在組件綁定它之後才可以運行。多個組件可以一次性綁定一個service,但是,當它們都取消綁定後,service將被銷毀。
Although this documentation generally discusses these two types of services separately, your service can work both ways—it can be started (to run indefinitely) and also allow binding. It's simply a matter of whether you implement a couple callback methods: onStartCommand() to allow components to start it and onBind() to allow binding.Regardless of whether your application is started, bound, or both, any application component can use the service (even from a separate application), in the same way that any component can use an activity—by starting it with an Intent. However, you can declare the service as private, in the manifest file, and block access from other applications. This is discussed more in the section about Declaring the service in the manifest.
這兩段比價簡單,只需要注意一下在manifest中聲明service為你的application私人就好了。
Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
謹慎處理:一個service運行在當前進程的主線程中,service不能為自己建立線程也不能在另外的進程運行。這就意味著,如果你的service將要執行一些CPU密集型操作,或者線程阻塞操作(such as MP3 playback or networking),你應該建立一個包含該service的線程來執行此類操作。通過使用另一個線程,你的application將減少了引發ANR錯誤的可能性,並且你的主線程將保留這來進行與使用者的互動活動。
延伸閱讀 :Should you use a service or a thread?
A service is simply a component that can run in the background even when the user is not interacting with your application. Thus, you should create a service only if that is what you need.If you need to perform work outside your main thread, but only while the user is interacting with your application, then you should probably instead create a new thread and not a service. For example, if you want to play some music, but only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), then stop it in onStop(). Also consider using AsyncTask or HandlerThread, instead of the traditional Thread class. See the Processes and Threading document for more information about threads.Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations.
有了前面的鋪墊,相比此處很容易裂理解吧,貼出來只是為了大家使用thread和service更容易的思考和抉擇。
好,現在來看一下Service的生命週期:
package me.androiddemo.canglangwenyue.androiddemo; android.app.Service;import android.content.Intent;import android.content.res.Configuration;import android.os.IBinder;import java.io.FileDescriptor;import java.io.PrintWriter;/** * Created by canglangwenyue on 12/7/14. */public class MyService extends Service {public MyService() { super();}@Overridepublic void onCreate() { super.onCreate(); Notification notification = new Notification(R.drawable.ic_launcher, getText(R.string.app_name), System.currentTimeMillis()); Intent notificationIntent = new Intent(this, MyService.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.hello_world), getText(R.string.hello_world), pendingIntent); startForeground(1, notification);}@Overridepublic void onStart(Intent intent, int startId) { super.onStart(intent, startId);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() { super.onDestroy();}@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig);}@Overridepublic void onLowMemory() { super.onLowMemory();}@Overridepublic void onTrimMemory(int level) { super.onTrimMemory(level);}@Overridepublic IBinder onBind(Intent intent) { return null;}@Overridepublic boolean onUnbind(Intent intent) { return super.onUnbind(intent);}@Overridepublic void onRebind(Intent intent) { super.onRebind(intent);}@Overridepublic void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent);}@Overrideprotected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { super.dump(fd, writer, args);} }
記得在manifest檔案裡註冊service,
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.androiddemo.canglangwenyue.androiddemo" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyService"></service> </application></manifest>
可以在onCreate()方法中啟動一個notification,是你的service顯示在通知欄,當然這裡只是簡單的顯示,具體可可以做更多的工作。然後在需要啟動service的activity裡面用
Intent intent = new Intent(this,MyService.class); startService(intent);
來開始一個 service。
好了,既然Service已經寫到這種程度了,那麼我們就再接再厲來看看IntentService吧,並比較一下如何在service與IntentService之間抉擇,讓大家更好地理解。
ServiceThis is the base class for all services. When you extend this class, it's important that you create a new thread in which to do all the service's work, because the service uses your application's main thread, by default, which could slow the performance of any activity your application is running.IntentServiceThis is a subclass of Service that uses a worker thread to handle all start requests, one at a time. This is the best option if you don't require that your service handle multiple requests simultaneously. All you need to do is implement onHandleIntent(), which receives the intent for each start request so you can do the background work.
Service
這是所有services的基類。當你extendsService之後,你是在你的application的main thread中建立了一個用於執行所有service's work的新線程,預設的,這種行為會降低你的activity正在執行的任何activity的效能。
IntentService
IntentService是Service類的子類,它用一個背景工作執行緒來處理所有的requests,而且一次只能執行一個。如果你不要求你的Service同時執行多個請求,那麼IntentService便是最好的選擇。你所需要做的只是實現onHandleIntent(),onHandleIntent()用來接收每個請求並在後台工作。使用Service使必須另開線程,而使用IntentService則不需要,因為framework預設實現了一個worker thread。IntentService自己維護了一個隊列,他會一個接一個的處理request。
好了,那麼來看一下,官網上IntentService的實現:
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) { } } } }}
好了,現在應該是很簡單了,有木有。注意IntentService一般和LocalBroadcastManager組合使用,從而使得IntentService將任務執行的任務狀態與結果返回給任務的發送方。
官方文檔地址:
API Guides
Reference
嗯嗯,就寫到這裡了。