編輯:關於Android編程
Service 是一個可以在後台執行長時間運行操作而不使用用戶界面的應用組件。服務可由其他應用組件啟動,而且即使用戶切換到其他應用,服務仍將在後台繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而所有這一切均可在後台進行。
服務基本上分為兩種形式:
啟動
當應用組件(如 Activity)通過調用 startService()
啟動服務時,服務即處於“啟動”狀態。一旦啟動,服務即可在後台無限期運行,即使啟動服務的組件已被銷毀也不受影響。已啟動的服務通常是執行單一操作,而且不會將結果返回給調用方。例如,它可能通過網絡下載或上傳文件。 操作完成後,服務會自行停止運行。
綁定
當應用組件通過調用 bindService() 綁定到服務時,服務即處於“綁定”狀態。綁定服務提供了一個客戶端-服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信(IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務才會運行。多個組件可以同時綁定到該服務,但全部取消綁定後,該服務即會被銷毀。
雖然本文檔是分開概括討論這兩種服務,但是您的服務可以同時以這兩種方式運行,也就是說,它既可以是啟動服務(以無限期運行),也允許綁定。問題只是在於您是否實現了一組回調方法:onStartCommand()(允許組件啟動服務)和 onBind()(允許綁定服務)。
無論應用是處於啟動狀態還是綁定狀態,抑或處於啟動並且綁定狀態,任何應用組件均可像使用活動那樣通過調用 Intent 來使用服務(即使此服務來自另一應用)。 不過,您可以通過清單文件將服務聲明為私有服務,並阻止其他應用訪問。
應重寫的最重要的回調方法包括:
1、onStartCommand()
啟動服務startService() -> 重寫 onStartCommand() 一旦執行此方法,服務即會啟動並可在後台無限期運行。 如果已實現此方法,則在服務工作完成後,需要通過調用 stopSelf()或stopService()來停止服務。(如果您只想提供綁定,則無需實現此方法。)
2、onBind()
綁定服務 bindService(),系統將調用此方法onBind()。在此方法的實現中,必須通過返回IBinder提供一個接口,供客戶端用來與服務進行通信。請務必實現此方法,但如果並不希望允許綁定,則應返回 null。
3、onCreate()
首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或
onBind()之前)。如果服務已在運行,則不會調用此方法。
4、onDestroy()
當服務不再使用且將被銷毀時,系統將調用此方法。服務應該實現此方法來清理所有資源,如線程、注冊的偵聽器、接收器等。 這是服務接收的最後一個調用。
如果組件通過調用 startService()啟動服務(這會導致對 onStartCommand()的調用),則服務將一直運行,直到服務使用 stopSelf()自行停止運行,或由其他組件通過調用 stopService()停止它為止。
如果組件是通過調用 bindService()來創建服務(且未調用 onStartCommand()),則服務只會在該組件與其綁定時運行。一旦該服務與所有客戶端之間的綁定全部取消,系統便會銷毀它。
為了確保應用的安全性,請始終使用顯式 Intent 啟動或綁定 Service ,且不要為服務聲明 Intent 過濾器。
創建啟動服務
從傳統上講,可以擴展Service , IntentService兩個類
Service該基類包含更多代碼,但如需同時處理多個啟動請求,則更適合使用該基類;
使用 IntentService顯著簡化了啟動服務的實現。但是,若要求服務執行多線程(而不是通過工作隊列處理啟動請求),則可擴展Service類來處理每個 Intent。為了便於比較,以下提供了 Service 類實現的代碼示例,該類執行的工作與使用IntentService的示例完全相同。也就是說,對於每個啟動請求,它均使用工作線程執行作業,且每次僅處理一個請求。
以下是使用 Service類的代碼示例:
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 5 * 1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
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();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
2. IntentService
這是 Service的子類,它使用工作線程逐一處理所有啟動請求。如果您不要求服務同時處理多個請求,這是最好的選擇。 您只需實現 onHandleIntent()方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執行後台工作。
擴展IntentService創建啟動服務,執行以下操作:
創建默認的工作線程,用於在應用的主線程外執行傳遞給 onStartCommand()的所有 Intent。
創建工作隊列,用於將一個 Intent 逐一傳遞給 onHandleIntent()實現,這樣您就永遠不必擔心多線程問題。
在處理完所有啟動請求後停止服務,因此您永遠不必調用 stopSelf()。
提供 onBind()的默認實現(返回 null)。
提供 onStartCommand()的默認實現,可將 Intent 依次發送到工作隊列和 onHandleIntent()實現。
綜上所述 :
只需實現 onHandleIntent()來完成客戶端提供的工作即可。(不過,您還需要為服務提供小型構造函數。)
以下是 IntentService的實現示例:
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("HelloIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
long endTime = System.currentTimeMillis() + 5 * 1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}
– 您只需要一個構造函數和一個 onHandleIntent()實現即可。
如果您決定還重寫其他回調方法(如 onCreate()、onStartCommand()或 onDestroy()),請確保調用超類實現,以便 IntentService能夠妥善處理工作線程的生命周期。
例如,onStartCommand()必須返回默認實現(即,如何將 Intent 傳遞給 onHandleIntent()):
@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);
}
除 onHandleIntent()之外,您無需從中調用超類的唯一方法就是 onBind()(僅當服務允許綁定時,才需要實現該方法)。
啟動服務
可以通過將 Intent,從 Activity 或其他應用組件啟動服務。Android 系統調用服務的 onStartCommand()
方法,並向其傳遞 Intent。(切勿直接調用onStartCommand()。)
例如,Activity 可以結合使用顯式 Intent 與 startService()
,啟動上文中的示例服務 (HelloSevice):
Intent intent = new Intent(this, HelloService.class);startService(intent);
startService()方法將立即返回,且 Android 系統調用服務的 onStartCommand()方法。如果服務尚未運行,則系統會先調用 onCreate(),然後再調用 onStartCommand()。
如果服務亦未提供綁定,則使用 startService()傳遞的 Intent 是應用組件與服務之間唯一的通信模式。但是,如果您希望服務返回結果,則啟動服務的客戶端可以為廣播創建一個 PendingIntent(使用getBroadcast()),並通過啟動服務的 Intent傳遞給服務。然後,服務就可以使用廣播傳遞結果。
多個服務啟動請求會導致多次對服務的 onStartCommand()進行相應的調用。但是,要停止服務,只需一個服務停止請求(使用 stopSelf() 或 stopService())即可。
停止服務
啟動服務必須管理自己的生命周期。也就是說,除非系統必須回收內存資源,否則系統不會停止或銷毀服務,而且服務在 onStartCommand()返回後會繼續運行。因此,服務必須通過調用 stopSelf()
自行停止運行,或者由另一個組件通過調用 stopService()來停止它。
一旦請求使用 stopSelf()或 stopService()停止服務,系統就會盡快銷毀服務。
但是,如果服務同時處理多個 onStartCommand()請求,則您不應在處理完一個啟動請求之後停止服務,因為您可能已經收到了新的啟動請求(在第一個請求結束時停止服務會終止第二個請求)。為了避免這一問題,您可以使用 stopSelf(int)確保服務停止請求始終基於最近的啟動請求。也就說,在調用 stopSelf(int)時,傳遞與停止請求的 ID 對應的啟動請求的 ID(傳遞給 onStartCommand()的 startId) 。然後,如果在您能夠調用stopSelf(int)之前服務收到了新的啟動請求, ID 就不匹配,服務也就不會停止。
注意:為了避免浪費系統資源和消耗電池電量,應用必須在工作完成之後停止其服務。 如有必要,其他組件可以通過調用 stopService()來停止服務。即使為服務啟用了綁定,一旦服務收到對 onStartCommand()的調用,您始終仍須親自停止服務。
創建綁定服務
綁定服務允許應用組件通過調用 bindService()與其綁定,以便創建長期連接(通常不允許組件通過調用startService()來啟動它)。
如需與 Activity 和其他應用組件中的服務進行交互,或者需要通過進程間通信 (IPC) 向其他應用公開某些應用功能,則應創建綁定服務。
要創建綁定服務,必須實現 onBind()回調方法以返回 IBinder,用於定義與服務通信的接口。然後,其他應用組件可以調用 bindService()來檢索該接口,並開始對服務調用方法。服務只用於與其綁定的應用組件,因此如果沒有組件綁定到服務,則系統會銷毀服務(您不必按通過 onStartCommand()
啟動的服務那樣來停止綁定服務)。
要創建綁定服務,首先必須定義指定客戶端如何與服務通信的接口。 服務與客戶端之間的這個接口必須是IBinder的實現,並且服務必須從 onBind()回調方法返回它。一旦客戶端收到 IBinder
,即可開始通過該接口與服務進行交互。
多個客戶端可以同時綁定到服務。客戶端完成與服務的交互後,會調用 unbindService()
取消綁定。一旦沒有客戶端綁定到該服務,系統就會銷毀它。
有多種方法實現綁定服務,其實現比啟動服務更為復雜,因此綁定服務將在有關綁定服務的單獨文檔中專門討論。
向用戶發送通知
一旦運行起來,服務即可使用 Toast 通知或狀態欄通知來通知用戶所發生的事件。
Toast 通知是指出現在當前窗口的表面、片刻隨即消失不見的消息,而狀態欄通知則在狀態欄提供內含消息的圖標,用戶可以選擇該圖標來采取操作(例如啟動 Activity)。
通常,當某些後台工作已經完成(例如文件下載完成)且用戶現在可以對其進行操作時,狀態欄通知是最佳方法。 當用戶從展開視圖中選定通知時,通知即可啟動 Activity(例如查看已下載的文件)。
如需了解詳細信息,請參閱 Toast 通知或狀態欄通知開發者指南。
在前台運行服務
前台服務被認為是用戶主動意識到的一種服務,因此在內存不足時,系統也不會考慮將其終止。 前台服務必須為狀態欄提供通知,狀態欄位於“正在進行”標題下方,這意味著除非服務停止或從前台刪除,否則不能清除通知。
例如,應該將從服務播放音樂的音樂播放器設置為在前台運行,這是因為用戶明確意識到其操作。 狀態欄中的通知可能表示正在播放的歌曲,並允許用戶啟動 Activity 來與音樂播放器進行交互。
要請求讓服務運行於前台,請調用 startForeground()。此方法取兩個參數:唯一標識通知的整型數和狀態欄的 Notification。例如:
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);
注意:提供給 startForeground()的整型 ID 不得為 0
要從前台刪除服務,請調用 stopForeground()。此方法取一個布爾值,指示是否也刪除狀態欄通知。 此方法絕對不會停止服務。
但是,如果您在服務正在前台運行時將其停止,則通知也會被刪除。
如需了解有關通知的詳細信息,請參閱創建狀態欄通知。
管理服務生命周期
服務的生命周期比 Activity 的生命周期要簡單得多。但是,密切關注如何創建和銷毀服務反而更加重要,因為服務可以在用戶沒有意識到的情況下運行於後台。
服務生命周期(從創建到銷毀)可以遵循兩條不同的路徑:
1、啟動服務
該服務在其他組件調用 startService()時創建,然後無限期運行,且必須通過調用 stopSelf()來自行停止運行。此外,其他組件也可以通過調用 stopService()來停止服務。服務停止後,系統會將其銷毀。
2、綁定服務
該服務在另一個組件(客戶端)調用 bindService()時創建。然後,客戶端通過 IBinder接口與服務進行通信。客戶端可以通過調用 unbindService()關閉連接。多個客戶端可以綁定到相同服務,而且當所有綁定全部取消後,系統即會銷毀該服務。 (服務不必自行停止運行。)
這兩條路徑並非完全獨立。也就是說,您可以綁定到已經使用 startService()啟動的服務。例如,可以通過使用 Intent(標識要播放的音樂)調用 startService()來啟動後台音樂服務。隨後,可能在用戶需要稍加控制播放器或獲取有關當前播放歌曲的信息時,Activity 可以通過調用 bindService()綁定到服務。在這種情況下,除非所有客戶端均取消綁定,否則 stopService() 或 stopSelf()不會真正停止服務。
實現生命周期回調
與 Activity 類似,服務也擁有生命周期回調方法,您可以實現這些方法來監控服務狀態的變化並適時執行工作。 以下框架服務展示了每種生命周期方法:
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
}
}
注:與 Activity 生命周期回調方法不同,您不需要調用這些回調方法的超類實現。
服務生命周期左圖顯示了使用 startService()所創建的服務的生命周期,右圖顯示了使用 bindService()所創建的服務的生命周期。
通過實現這些方法,您可以監控服務生命周期的兩個嵌套循環:
服務的 整個生命周期 從調用 onCreate()開始起,到 onDestroy()返回時結束。與 Activity 類似,服務也在 onCreate()中完成初始設置,並在 onDestroy()中釋放所有剩余資源。例如,音樂播放服務可以在onCreate()中創建用於播放音樂的線程,然後在 onDestroy()中停止該線程。無論服務是通過 startService()還是 bindService()創建,都會為所有服務調用 onCreate()和onDestroy()方法。
服務的 有效生命周期 從調用 onStartCommand()或 onBind()方法開始。每種方法均有 Intent對象,該對象分別傳遞到 startService()或 bindService()。對於啟動服務,有效生命周期與整個生命周期同時結束(即便是在 onStartCommand()返回之後,服務仍然處於活動狀態)。對於綁定服務,有效生命周期在 onUnbind()返回時結束
注:盡管啟動服務是通過調用 stopSelf()或 stopService()來停止,但是該服務並無相應的回調(沒有onStop()回調)。因此,除非服務綁定到客戶端,否則在服務停止時,系統會將其銷毀—onDestroy()是接收到的唯一回調。
上圖說明了服務的典型回調方法。盡管該圖分開介紹通過 startService()創建的服務和通過bindService()創建的服務,但是請記住,不管啟動方式如何,任何服務均有可能允許客戶端與其綁定。因此,最初用 onStartCommand()(通過客戶端調用 startService())啟動的服務仍可接收對 onBind()的調用(當客戶端調用 bindService()時)。
Android 側滑菜單的實現,參考網上的代碼,實現側滑菜單。最重要的是這個動畫類UgcAnimations,如何使用動畫類來側滑的封裝FlipperLayout。&nb
OKHttp3是如今非常流行的Android網絡請求框架,那麼如何利用Android實現斷點續傳呢,今天寫了個Demo嘗試了一下,感覺還是有點意思准備階段我們會用到OKH
概述 RSA是目前最有影響力的公鑰加密算法,該算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困 難,因此可以
Android事件驅動編程-基於EventBus(一) 雖然在Android開發具有某些事件驅動的特性,但它還遠不是純粹的事件驅動架構。這算是好事還是壞事呢