android service

轉載請註明出處:http://blog.csdn.net/zhouli_csdn/article/details/45485871 


     service是andorid的一個可以長期運行在後臺的一個組件。它可以從一個應用組件中啓動,即使用戶切換到其它應用,他仍將在後臺運行。一個組件可以綁定到一個服務並與之交互,甚至進程間通信(IPC)。例如服務可以在後臺執行網絡交易,音樂播放,文件輸入輸出,與內容提供者交互。

兩種方式啓動服務:

started:通過在一個應用程序組件中調用startService()方法啓動服務。通過該方法啓動服務後,即使啓動它的組件已經銷燬,它仍將繼續在後臺運行。通常啓動服務之星一個操作,並且不會向調用者返回一個值。可以在後臺執行上傳或者下載任務,當任務完成後必須自己停止自己。
bound:應用程序組件通過調用bindService()啓動服務,並提供一個客戶端服務器的綁定接口允許組件與服務交互甚至進程間通信。一個綁定服務只有在一個組件綁定到它時纔會運行,同時可以有多個組件綁定到一個服務,但是隻有所有的組件都解綁時,服務纔會被銷燬。
       服務可以以兩種方式運行,實現onStartCommond()方法運行startService,實現onBind()方法允許bindService。
       不管服務以哪種方式運行,或者兩者都有,任何應用程序組件都可以使用它,甚至其它應用程序。同樣的,任何應用程序組件都可以使用一個Activity(通過Intent)。然而,你可以在manifest中聲明這個服務爲私有的,阻止其它應用程序訪問。
警告:服務運行在主線程的託管進程。服務不創建自己的線程,也不運行在一個單獨的進程(除非指定)。這意味着如果你想讓服務做一些CPU密集工作或者阻塞工作,你需要單獨創建一個線程去做。

基本內容:

       必須繼承Service或者它的子類。必須覆蓋一些處理生命週期的回調方法並提供一個機制可以使組件綁定到它。
onStartCommond:當一個應用組件調用startService方法時,系統纔會調用這個方法。一旦這個方法執行,服務將會一直執行下去。如果你實現了這個方法,當任務完成時,你必須調用stopService或者stopSelf方法結束它。如果你僅僅向綁定,不必實現這個方法。
onBind:一個應用組件調用bindService時,系統會調用這個方法。在你的實現中,你必須實現一個接口並返回一個IBinder使調用者可以與該服務通信.如果你不允許綁定,你必須返回null。
onCreate:統會在調用onStartCommond或者onBind之前調用該方法。如果服務已經在運行,該方法不會被調用。
onDestroy:當服務不再使用而且正在被銷燬時會被系統調用。你的服務必須實現該方法以清理資源。例如:線程、註冊的監聽器、廣播等。這是服務接收到的最後一個請求。
       組件通過調用startService時,系統會調用onStartCommond方法,這時該服務只能通過調用stopSelf或者其它組件調用stopService停止該服務。如果一個組件調用bindService創建一個服務, 並且onStartCommond沒有被調用,那麼當該服務和所有的clients解綁時,系統纔會銷燬這個服務。

       系統將會在資源不足時強制結束service。如果一個服務被綁定到一個用戶焦點的Activity,那麼它就不太可能被殺死,如果一個service被聲明爲前臺服務,那麼它將幾乎不會被殺死。否則,如果服務長時間運行,系統會降低它的位置,那麼它將很容易被殺死。如果你啓動服務,你必須很好的處理系統重啓服務。系統在結束服務後,會根據onStartCommond的返回值決定是否重啓你的服務。

在manifest中聲明服務:

你必須在manifest中聲明所有的服務。在application的子節點添加一個service。
可以在service元素包含其它屬性,例如:權限,service在哪一個進程中運行。只有android:name屬性使必須有的。可以爲服務定義intent filters允許其它組件使用意圖啓動該服務。通過定義intent filters,安裝在設備上的任何應用都可以啓動它。如果你僅僅在自己的應用中使用(其它應用不用),那麼你不應該提供intent filters。即使你使用了intent filters,android:exported="false"可以確保服務只能被自己的應用使用。

創建一個started service:

       通過傳遞一個intent和數據,startService啓動服務,並且在onstartCommond方法中得到該intent。
       例如:一個activity要保存一些數據到在線數據庫中。可以通過intent傳遞數據給service,在onstartCommond中接收數據,連接到網絡完成數據庫操作。任務完成後,結束自己。
有兩個類可以拓展來創建一個started service:
service類:所有服務的基類。繼承這個類,必須自己創建一個線程完成耗時的任務。
IntentService:該服務順序執行每一個請求,如果你不需要同時執行任務,可以使用它。你只需要實現onHandleIntent,接受intent,完成任務。
IntentService:
     1)創建一個線程執行所有傳遞給onStartCommond的意圖。
     2)創建一個隊列,一次只傳遞一個intent給onHandleIntent,所以你不必擔心多線程。
     3)所有的請求執行完成後,會自己調用stopSelf。
     4)提供一個默認返回null的onBind
     5)提供一個默認的onStartCommond,它將intent傳遞給工作隊列,然後在給onHandleIntent。
你只需要實現onHandleIntent和實現一個構造函數:
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,onStartCommond,onDestroy,記得調用父類函數。只有onHandleIntent和onBind你不需要調用父類函數,如果你的服務允許綁定,你需要實現onBind。
下面的例子仿造IntentService,一次只處理一個請求:
 }
          }
          // 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(); 
  }
}


注意onStartCommond必須返回以下整數值中的一個:
START_NOT_STICKY:系統在結束你的服務後,並不會重新啓動它,除非有沒有解決的intent時。
START_STICKY:如果系統殺死服務時,會從新啓動服務,但是並不會將以前的intent傳遞過來,而是傳遞null,除非有沒有解決的intnet來啓動服務。比較適合媒體播放器或者類似的服務。
START_REDELIVER_INTENT:系統殺死服務後,會重新創建服務,並且將上一次的intnent傳遞過來。如果有爲執行的intent,會傳遞。這適合那些需要恢復的服務。例如:下載文件

啓動一個service:

startService方法調用後,系統hi調用onStartCommond方法,如果服務還沒開始運行,那麼系統會先調用onCreate。
如果服務沒有提供綁定,那麼通過startService傳遞的intent是唯一client和service的通信。然而如果你希望服務返回一個結果,那麼啓動這個服務的客戶端可以爲一個廣播(getBroadcast)創建一個PendingIntent。你可以這個PendingIntent放在intent中傳遞給service,這樣service就可以用broadcast來傳遞結果。
多個請求服務startService會多次調用onStartCommond方法,但是stopSelf或stopService只會調用一次。

停止一個服務:

如果你的服務在處理多個請求,如果你在一個啓動服務之後結束service,將會結束第二次請求。爲了避免這個問題,你可以使用stopSelf(int),如果你調用stopSelf(int),將會傳遞啓動它的Id值,如果此時,服務接到另一個請求在你還沒執行stopSelf(int)之前,因爲int值不匹配,並不會結束它。
警告:服務工作完成後,最好結束service,避免浪費資源和電量。

創建一個綁定服務:

如果你希望你的服務和Activities和其它的組件可以與之通信,或者暴露你的一些功能給其它應用程序,通過(IPC),可以使用bindService。
你必須實現onBind,返回一個接口(定義了client如何與服務通信)。其它應用程序組件可以通過調用bindService返回IBinder,通過IBinder與服務通信。
bindService很複雜,將會在單獨的一個章節講解。

發送通知給用戶:

服務一旦運行起來,可以通過Toasts或者Notifications通知用戶。通常使用Notifications。

在前臺運行服務:

一個前臺服務必須提供一個Notification,並且這個通知不能被取消,除非這個service被停止或者從前臺服務移除。
例如:
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);

注意:這個整數ID不能爲0.
移除前臺服務調用stopForceground,傳遞一個boolean值,表示是否移除狀態欄通知。這個方法並不結束服務。如果你結束一個正在前臺運行的服務,那麼這個狀態欄通知也會被移除。

管理服務的生命週期:

生命週期兩條路線:
a started service:
a binded service:
這個兩個路徑並不是完全獨立,你可以在startService之後,在綁定它。在這種情況下,stopService或者stopSelf並不會結束service,只有所有的clients解綁之後,纔會銷燬服務。
生命週期方法:
public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}


注意:你不必調用父類的方法。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章