服務 android多線程編程 服務的基本用法 服務的生命週期 服務技巧
服務(Service): 在Android中實現程序後臺運行的解決方案,本身的運行並不依賴於用戶可視的UI界面。
適用:
- 並不依賴於用戶可視的UI界面(不一定,前臺Service就是與Notification界面結合使用的)
- 不需要和用戶交互而且要求長時間運行
服務依賴於創建服務的所在的應用程序進程。(進程被殺死,依賴該進程的服務停止)
服務並不會自動開啓線程,因此需要在Service內部創建子線程。
服務基本用法:
Service分類:
Started Service:被一個組件調用startService()開啓的Service。
- 擴展Service:
這是所有服務的基類。擴展這個類的時候,特別重要的一點是,需要創建一個新的線程來做服務任務,因爲service默認是運行在你的主線程(UI線程)中的,它會使你的主線程運行緩慢。 - 擴展IntentService:
service的子類,在一個工作線程(子線程)中處理所有的啓動請求。需要是實現onHandlerIntent()方法,通過這個函數處理接受的每一個啓動請求。 (Android提供的便於創建異步,能自動停止的service)
- 擴展Service:
service的onStartCommand()方法被調,根據傳遞intent開啓Service,擁有一個獨立於開始它的組件(不是進程)的生命週期。
默認service運行在聲明它的應用的同一個進程裏面,而且在應用的主線程裏面。
- Bound Service:
與Activity相綁定的service。
定義一個服務:
- AndroidManifest.xml 註冊:Service屬於四大組件之一,無論是Started Service和Bound Service,都有Service基類繼承而來,都需要在AndroidManifest.xml中聲明.
<service android:enabled=["true" | "false"]
android:exported=["true" | "false"] //是否能被其他程序組件調用或交互
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string" //Service類名
android:permission="string" //權限聲明
android:process="string" > //設置具體的進程名稱
. . .
</service>
- 完成Service類的繼承,自定義MyService類,重寫相應辦法:
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) { //綁定方法,唯一抽象方法
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService" , "in onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "in onStartCommand");
return super.onStartCommand(intent,flags,startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyService", "in onDestroy");
}
}
onCreate(…),onStartCommand(…),onDestroy()爲Service相應生命週期階段的回調函數.
onBind(…)函數是Service基類中的唯一抽象方法,子類都必須重寫實現,對於Bound Service,其返回值才具有意義。
啓動和停止服務:
通過startservice() stopservice(),傳遞intent,開啓,停止相應服務。
在service內部任一位置,通過調用stopSelf()方法停止服務。
case R.id.start_service:
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);
break;
活動與服務進行通信(Bound Service):
通過擴展Binder類創建Bound Service的步驟如下:
- 在Service類中,創建一個Binder實例,包含客戶端能調用的公共方法,返回當前服務對象,在onBind()方法中返回Binder實例
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder{
public void startDownload(){
Log.d("MyService","startDownload executed");
}
public int getProgress(){
Log.d("MyService","getProgress executed");
return 0;
}
}
...........................
@Override //返回實例
public IBinder onBind(Intent intent) {
return mBinder;
}
}
- 自定義的ServiceConnection中實現onServiceConnected(ComponentName name, IBinder binder)方法,獲取Service端Binder實例,通過獲取的Binder實例進行Service端其他公共方法的調用
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName namee) {
}
@Override
public void onServiceConnected(ComponentName name,IBinder service) {
downloadBinder = (MyService.DownloadBinder) service; //獲取實例
downloadBinder.startDownload(); //完成對於公共方法的調用
downloadBinder.getProgress();
}
};
- 通過bindService(intent,connection,flag)方法,實現Activity與Service的通信。
intent : 連接相應的ActivityyuService
connection:已完成重寫onServiceConnected()方法的ServiceConnection內部類對象。
flag:關聯模式,採用BIND_AUTO_CREATE即可。
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_ABOVE_CLIENT);
break;
- 通過調用unbindService()方法,解除綁定:
unbindService(connection);
服務的生命週期:
生命週期回調方法:
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
}
}
注:
- onCreate()方法在service沒有被創建的情況下,啓動服務,纔會被調用。
- onStartCommand()方法在每一次調用startService()方法時,都會被執行一次,但是並不會創建新的實例。
- 通過bindService()方法獲取了持久連接,則必須調用unbindService()方法,解除綁定,纔可以調用stopService()方法,結束服務。
前臺服務:
由於Service的系統優先級比較低,在內存不足的情況下,可能被系統回收。爲了避免被系統回收正在運行的Service,使Service可以一直保持運行狀態——前臺服務
前臺服務將會在狀態欄有一個正在運行的圖標,類似於Notification效果。
實現:
- 構建Notification對象,對其顯示方式進行設置
- PendingIntent的設置,實現對於點擊意圖的設置
- 通過startForeground(Id, notification); ID爲通知的Id,notification爲構建的Notification對象,將Service轉變爲前臺服務。
Notification notification = new Notification(R.drawable.ic_launcher,
"Notification comes", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title", "This is content",
pendingIntent);
startForeground(1, notification);
Android多線程基礎:基本與java多線程編程使用相同的語法。
- 創建子線程:
class MyThread extends Thread{
@Override
public void run(){
//耗時邏輯
}
}
---------------------------------------------------
//使用實現Runnable接口定義線程 (耦合性高?)
class MyThread implements Runnable(){
@Override
public void run(){
//耗時邏輯
}
}
-----------------------------------------------------
//匿名類方式
new Thread (new Runnable(){
@Override
public void run(){
//耗時邏輯
}
}).start();
- 啓動線程:
new Thread().start();
----------------------------------------------------------
MyThread myThread = new MyThread();
new Thread(myThread).start;
Android的UI操作屬於線程不安全,即必須在主線程中進行對於UI的操作。
使用異步消息機制,在子線程中執行耗時操作,根據任務結果更新UI。
方法一:異步消息處理:Message,Handle,MessageQueue,Looper構成,詳細解釋。
基礎練習
方法二:AsyncTask: Android提供的輕量級的異步類,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最後反饋執行的結果給UI主線程.
同樣基於異步消息處理機制,Android進行了較好的封裝。
優點:
- 簡單,快捷
- 過程可控
缺點:
- 在使用多個異步操作和並需要進行Ui變更時,就變得複雜起來.
AsyncTask直接繼承於Object類,位置爲android.os.AsyncTask。要使用AsyncTask工作我們要提供三個泛型參數,並重載幾個方法(至少重載一個)。
AsyncTask定義了三種泛型類型 Params,Progress和Result。
- Params: 啓動任務執行的輸入參數,比如HTTP請求的URL。
- Progress: 後臺任務執行的百分比。
- Result: 後臺執行任務最終返回的結果,比如String。
最少寫以下這兩個方法:
- doInBackground(Params…) 後臺執行,比較耗時的操作都可以放在這裏。注意這裏不能直接操作UI。此方法在後臺線程執行,完成任務的主要工作,通常需要較長的時間。在執行過程中可以調用publicProgress(Progress…)來更新任務的進度。
- onPostExecute(Result) 相當於Handler 處理UI的方式,在這裏面可以使用在doInBackground 得到的結果處理操作UI。 此方法在主線程執行,任務執行的結果作爲此方法的參數返回。
補充方法:
- nProgressUpdate(Progress…) 可以使用進度條增加用戶體驗度。 此方法在主線程執行,用於顯示任務執行的進度。
- onPreExecute() 這裏是最終用戶調用Excute時的接口,當任務執行之前開始調用此方法,可以在這裏顯示進度對話框。
- onCancelled() 用戶調用取消時,要做的操作
使用AsyncTask類,以下是幾條必須遵守的準則:
- Task的實例必須在UI thread中創建;
- execute方法必須在UI thread中調用;
- 不可以手動調用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法;
- 該task只能被執行一次,否則多次調用時將會出現異常;
AsyncTask基礎練習
IntentService:
由於Serice默認運行與主線程,在處理耗時邏輯情況下,可能出現ANR情況。
可以通過多線程編程,在Service的具體方法內開啓線程,在子線程中處理耗時邏輯,通過stopSelf停止。
public itn onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable() { //開啓子線程
@Override
public void run() {
//耗時邏輯
stopSelf();
}
}).start();
return super.onStartCommand(intent,flags,startId);
}
}
InentService:
已由Android封裝,自動開啓線程,自動調用stopSelf()方法的InentService類。
IntentService通過worker thread處理每個Intent對象,執行完所有工作後自動停止Service。
實現:通過複寫onHandleIntent()方法,構造。
- 創建一個與應用程序主線程分開worker thread用來處理所有通過傳遞過來的Intent請求
- 創建一個work queue,一次只傳遞一個intent到onHandleIntent()方法中,從而不用擔心多線程帶來的問題
- 當處理完所有請求後自動停止服務,而不需要我們自己調用stopSelf()方法
- 默認實現了onBind()方法,返回值爲null
- 默認實現了onStartCommand()方法,這個方法將會把我們的intent放到work queue中,然後在onHandleIntent()中執行
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
} //耗時操作 在子線程中運行
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
使用上與一般Service沒有很大差別。
服務的最佳實踐:
後臺執行的定時任務 (通過定時任務,實現循環)