service(服務)是安卓中的四大組件之一,它通常用作在后臺處理耗時的邏輯,與Activity一樣,它存在自己的生命周期,也需要在清單文件中配置相關信息,本博客將對Service的各個知識點進行詳細講解。
一Service的基本用法:
1使用本地服務
1)服務的啟動方式
1通過Context的startService()方法啟動服務 :以該方法啟動的服務,開啟該服務的應用組件(如Activity)與該Service不存在關聯關系,即使開啟該服務的Activity被銷毀,Service任能夠一直在后臺運行。通常,開啟的服務執行一個單獨的操作且不需向調用者返回一個結果。比如,可能從網絡進行下載或者上傳一個文件。當任務完成,服務就該自我停止。使用服務于使用Activity非常相似,都是先繼承其對應的基類,然后重寫其中重要的方法,這些方法就是關于其生命周期回調的方法。代碼如下所示:
[java] view plaincopy
public ?class ?MyService?extends ?Service?{???? ????public ?static ?final ?String?TAG?=?"MyService" ;?? ?? ????@Override ?? ????public ?void ?onCreate()?{?? ????????super .onCreate();?? ????????Log.d(TAG,?"onCreate()?executed" );?? ????}?? ?? ????@Override ?? ????public ?int ?onStartCommand(Intent?intent,?int ?flags,?int ?startId)?{?? ????????Log.d(TAG,?"onStartCommand()?executed" );?? ????????return ?super .onStartCommand(intent,?flags,?startId);?? ????}?? ?????? ????@Override ?? ????public ?void ?onDestroy()?{?? ????????super .onDestroy();?? ????????Log.d(TAG,?"onDestroy()?executed" );?? ????}?? ?? ????@Override ?? ????public ?IBinder?onBind(Intent?intent)?{?? ????????return ?null ;?? ????}?? ?? }??
然后再Activity中使用
[java] view plaincopy
Intent?startIntent?=?new ?Intent(this ,?MyService.class );???? startService(startIntent);???
即可開啟該服務,程序運行結果如下:
從程序的運行結果來看,可以知道當啟動一個Service的時候,會調用該Service中的onCreate()和onStartCommand()方法。
當我們在次點擊啟動服務的按鈕,程序運行結果如下:
可以看到,此時只輸出onStartCommand() executed。這說明此時只執行了onStartCommand()方法,而未執行onCreate(),這說明onCreate()方法只會在Service第一次被創建的時候調用,如果當前Service已經被創建過了,則即使多次調用startService()方法,onCreate()方法都不會再執行,這一點非常類似數據庫操作中的open一個數據庫。
當然上述的例子僅僅只是為了說明上述知識點,因為Service中的代碼也僅僅只是打印出log而已,而事實上Service的使用是為了處理一些耗時操作的,如網絡請求,文件上傳與下載,但都是重寫其某個生命周期函數,如onStart(Intent intent, int startId),onDestroy()在這些函數中完成自己的業務邏輯的處理,下面的代碼是使用服務來進行網絡通信的一個例子。
[java] view plaincopy
public ?class ?GetMsgService?extends ?Service?{??????private ?Client?client;?? ????private ?boolean ?isStart;?? ????private ?SharePreferenceUserInfoUtil?util;?? ????private ?ClientInputThread?cit;?? ????@Override ?? ????public ?IBinder?onBind(Intent?intent)?{?? ?????????? ????????return ?null ;?? ????}?? ?? ????@Override ?? ????public ?void ?onCreate()?{?? ?????????? ????????super .onCreate();?? ????????client=((MyApplication)?getApplication()).getClient();?? ????}?? ?? ????@Override ?? ????public ?void ?onStart(Intent?intent,?int ?startId)?{?? ?????????? ????????super .onStart(intent,?startId);?? ????????util?=?new ?SharePreferenceUserInfoUtil(getApplicationContext(),?? ????????????????Constants.SAVE_USER);?? ????????? ????????new ?Thread(){?? ???????????????public ?void ?run()?? ???????????????{?? ????????????????????try ?{?? ????????????????????????isStart=client.create();?? ????????????????????}?catch ?(UnknownHostException?e)?{?? ?????????????????????????? ????????????????????????e.printStackTrace();?? ????????????????????}?catch ?(IOException?e)?{?? ?????????????????????????? ????????????????????????e.printStackTrace();?? ????????????????????}?? ?????????????? ?????????????? ?????????????????????????????????????? ????????????????if (isStart)?? ????????????????{?? ????????????????????cit=client.getClientInputThread();?? ????????????????????if (cit!=null )?? ????????????????????{?? ????????????????????????cit.setMessageListener(new ?MessageListener()?{?? ?????????????????????????????? ????????????????????????????public ?void ?getMessage(TransportObject?msg)?{?? ?????????????????????????????????? ????????????????????????????????if (msg!=null &&msg?instanceof ?TransportObject)?? ????????????????????????????????{?? ?????????????????????????????????????? ????????????????????????????????????Intent?intent=new ?Intent();?? ????????????????????????????????????intent.setAction(Constants.ACTION_MSG);?? ????????????????????????????????????intent.putExtra(Constants.MSG,?msg);?? ????????????????????????????????????sendBroadcast(intent);?? ????????????????????????????????}?? ????????????????????????????}?? ????????????????????????});?? ????????????????????}?? ????????????????????else ?{?? ????????????????????????Log.i("GetMsgService" ,"服務器端連接暫時出錯" );?? ?????????????????????? ????????????????????}?? ????????????????}?? ???????????????????? ???????????????}?? ???????????}.start();?? ????}?? ?? ????@Override ?? ????public ?void ?onDestroy()?{?? ?????????? ????????super .onDestroy();?? ????????ClientOutputThread?out=client.getClientOutputThread();?? ????????TransportObject<User>?msg=new ?TransportObject<User>(TranObjectType.LOGOUT);?? ????????User?user=new ?User();?? ????????user.setId(Integer.parseInt(util.getId()));?? ????????msg.setObject(user);?? ????????out.setMsg(msg);?? ?????????? ????????out.setStart(false );?? ????????client.getClientInputThread().setStart(false );?? ?????????? ?????????? ?????????? ????}?? ?????? ?????? ?? }??
可以看到,我們在getMsgService的onStart方法中開啟了一個線程用來進行客戶端從服務器端讀取信息的操作,在onDestroy()方法中關閉網絡請求的操作。
2通過Context的bindService()方法啟動服務 :顧名思義,以該方法啟動的服務,開啟該服務的應用組件(如Activity)與該Service被綁定在一起,通常用這種方式開啟的服務是為了與開啟該服務的應用組件(如Activity)進行消息通信。
首先我們來看一下bindService的簽名:
[java] view plaincopy
bindService(Intent?service,?ServiceConnection?conn,?int ?flags)??
其中service參數是通過intent指定要啟動的Service。
conn參數是一個ServiceConnection對象,該對象用于監聽訪問者與service之間的連接情況,當訪問者與Service連接成功時會回調該類的onServiceConnected(ComponentName name, IBinder service)方法,然后將服務中創建的Ibinder對象(此時在Service的onBinder方法中需要返回該Ibinder對象)傳遞給第二個參數service,通過該Ibinder對象就能與Service進行通信。
第三個參數flags指定綁定時是否自動創建Service,一般我們指定為BIND_AUTO_CREATE(自動創建,如果傳入0表示不自動創建)示例代碼如下:
Service中的代碼:
[java] view plaincopy
public ?class ?MyService?extends ?Service?{???? ????public ?static ?final ?String?TAG?=?"MyService" ;?? ?? ????private ?MyBinder?mBinder?=?new ?MyBinder();?? ?? ????@Override ?? ????public ?void ?onCreate()?{?? ????????super .onCreate();?? ????????Log.d(TAG,?"onCreate()?executed" );?? ????}?? ?? ????@Override ?? ????public ?int ?onStartCommand(Intent?intent,?int ?flags,?int ?startId)?{?? ????????Log.d(TAG,?"onStartCommand()?executed" );?? ????????return ?super .onStartCommand(intent,?flags,?startId);?? ????}?? ?? ????@Override ?? ????public ?void ?onDestroy()?{?? ????????super .onDestroy();?? ????????Log.d(TAG,?"onDestroy()?executed" );?? ????}?? ?? ????@Override ?? ????public ?IBinder?onBind(Intent?intent)?{?? ????????return ?mBinder;?? ????}?? ?? ????class ?MyBinder?extends ?Binder?{?? ?? ????????public ?void ?doSomething()?{?? ????????????Log.d("TAG" ,?"doSomething()?executed" );?? ?????????????? ????????}?? ?? ????}?? ?? }??
Activity中的代碼:
[java] view plaincopy
public ?class ?MainActivity?extends ?Activity??{?? ??...?? private ?ServiceConnection?connection?=?new ?ServiceConnection()?{???????? ????????@Override ???? ????????public ?void ?onServiceDisconnected(ComponentName?name)?{???? ????????}???? ???? ????????@Override ???? ????????public ?void ?onServiceConnected(ComponentName?name,?IBinder?service)?{???? ????????????myBinder?=?(MyService.MyBinder)?service;???? ????????????myBinder.doSomething();???? ????????}???? ????};???? ????protected ?void ?onCreate(Bundle?savedInstanceState)?{???? ????????super .onCreate(savedInstanceState);???? ????????setContentView(R.layout.activity_main);???? ????Intent?bindIntent?=?new ?Intent(this ,?MyService.class );???? ????????bindService(bindIntent,?connection,?BIND_AUTO_CREATE);?? ????}?? ??...?? ?? }??
即在服務中定義一個IBinder的實例,然后在Service的public IBinder onBind(Intent intent)方法中將其返回,在Activity中定義一個ServiceConnection類的實例,在其onServiceConnected(ComponentName name, IBinder service)方法中獲取Service中 返回IBinder對象,利用該對象即可調用Service中的方法進行相互通信。
注意:一個服務在進程中的主線程運行——一個服務不會創建自己的線程,也不會在另外的進程運行(除非另外指定)。這意味著,如果服務需要做一些頻繁占用CPU的工作或者會發生阻塞的操作,你需要在服務中另開線程執行任務。避免程序出現ANR。
2使用AIDL跨進程調用服務:
此種情況與上述介紹的使用bindService方法開啟的綁定本地的大的框架基本相同,只不過使用AIDL來實現跨進程調用,關于此種情況的介紹,請參看我的博客:安卓中不同APP之間的消息通信中相關的內容。
二Service與線程的關系及IntentService:
事實上Service與線程之間沒多大關系,我們之所以把Service與線程放在一起談論,是為了更清楚的明白在哪些情況下用服務哪些情況下用線程,哪些情況下在服務中開啟一個線程,因為Service默認在主線程中運行,不能進行耗時操作,這也是IntentService存在的原因。因為IntentService會創建單獨的worker線程來處理intent請求,不需要自己創建一個子線程。
IntentService處理流程 創建默認的一個 worker 線程處理傳遞給 onStartCommand() 的所有 intent ,不占據應用的主線程 創建一個工作隊列一次傳遞一個 intent 到你實現的 onHandleIntent() 方法,避免了多線程 在所有啟動請求被處理后自動關閉服務,不需要調用 stopSelf() 默認提供 onBind() 的實現,且返回 null 默認提供 onStartCommand() 的實現,實現發送intent到工作隊列再到onHandleIntent() 方法實現。
正因為如此,所以使用IntentService無需重寫onBind(),onStartCommand(),只需重寫onHandleIntent() 即可。示例代碼如下:
[java] view plaincopy
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)?{?? ????????}?? ??????}?? ????}?? ??}?? }??
三Service的生命周期
我們先來看一下谷歌官方圖片:
從上述圖片可以看到兩種不同的啟動方式其生命周期也不同:
啟動的服務:? startService()->onCreate()->onStartCommand()->running->stopService()/stopSelf()->onDestroy()->stopped? 其中,服務未運行時會調用一次onCreate(),運行時不調用。 綁定的服務:? bindService()->onCreate()->onBind()->running->onUnbind()->onDestroy()->stopped 服務起始于 onCreate() ,終止于 onDestory() 服務的開關過程,只有 onStartCommand() 可多次調用,其他在一個生命周期只調用一次。 這兩個過程不是完全獨立,也可以綁定一個由 startService() 啟動過的服務
四如何創建不被系統殺死的服務
服務不被殺死包括三種情況
1.系統根據資源分配情況殺死服務
2.用戶通過 settings -> Apps -> Running -> Stop 方式殺死服務
3.用戶通過 settings -> Apps -> Downloaded -> Force Stop 方式殺死服務
第一種情況:
用戶不干預,完全靠系統來控制,辦法有很多。比如 onStartCommand() 方法的返回值設為 START_STICKY ,服務就會在資源緊張的時候被殺掉,然后在資源足夠的時候再恢復。當然也可設置為前臺服務,使其有高的優先級,在資源緊張的時候也不會被殺掉。
關于?onStartCommand() 方法的返回值做一下簡單的介紹:
START_STICKY:如果service進程被kill掉,保留service的狀態為開始狀態,但不保留遞送的intent對象。隨后系統會嘗試重新創建service,由于服務狀態為開始狀態,所以創建服務后一定會調用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動命令被傳遞到service,那么參數Intent將為null。 START_NOT_STICKY:“非粘性的”。使用這個返回值時,如果在執行完onStartCommand后,服務被異常kill掉,系統不會自動重啟該服務。 START_REDELIVER_INTENT:重傳Intent。使用這個返回值時,如果在執行完onStartCommand后,服務被異常kill掉,系統會自動重啟該服務,并將Intent的值傳入。 START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill后一定能重啟。 第二種情況: 用戶干預,主動殺掉運行中的服務。這個過程殺死服務會通過服務的生命周期,也就是會調用 onDestory() 方法,這時候一個方案就是在 onDestory() 中發送廣播開啟自己。這樣殺死服務后會立即啟動。如下:
在onCreate中注冊廣播,用來開啟服務,在服務的 onDestroy()中發送廣播通知服務開啟自己,代碼如下:
[java] view plaincopy
public ?void ?onCreate()?{?????? ??super .onCreate();?? ??mBroadcast?=?new ?BroadcastReceiver()?{?? ????@Override ?? ????public ?void ?onReceive(Context?context,?Intent?intent)?{?? ???????? ??????Intent?a?=?new ?Intent(ServiceA.this ,?ServiceA.class );?? ??????startService(a);?? ????}?? ??};?? ??mIF?=?new ?IntentFilter();?? ??mIF.addAction("listener" );?? ??registerReceiver(mBroadcast,?mIF);?? }?? @Override ??public ?void ?onDestroy()?{?????? ??super .onDestroy();?? ??Intent?intent?=?new ?Intent();?? ??intent.setAction("listener" );?? ??sendBroadcast(intent);?? ??unregisterReceiver(mBroadcast);?? }??
第三種情況: 強制關閉就不好解決。這個好像是從包的level去關的,不是走的Service的完整的生命周期。所以在服務里加代碼是無法被調用的。處理這個情況的唯一方法是屏蔽掉 force stop 和 uninstall 按鈕,讓其不可用。
好了,以上就是本人理解的關于Service的相關知識,看官如果覺得不錯請不要吝嗇點擊一下下方的“頂”按鈕給我一點鼓勵哦!
總結
以上是生活随笔 為你收集整理的安卓服务Service详解 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。