摘要:注意每個必須在中通過來聲明。執(zhí)行具體的下載任務(wù)接下來我們在中通過來綁定和解除綁定可以看到,這里我們首先創(chuàng)建了一個的匿名類,在里面重寫了方法和方法,這兩個方法分別會在與建立關(guān)聯(lián)和解除關(guān)聯(lián)的時候調(diào)用。
前言
Hi,大家好,上一期我們講了如何使用BroadcastReceiver,這一期我們講解Android四大組件之Service相關(guān)知識。每天一篇技術(shù)干貨,每天我們一起進(jìn)步。
耐心專注不僅僅是美德,更是一筆財富。
1.簡介與定義Service是一個可以在后臺執(zhí)行長時間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。Service可由其他應(yīng)用組件啟動,而且即使用戶切換到其他應(yīng)用,Service仍將在后臺繼續(xù)運(yùn)行。 此外,組件可以綁定到Service,以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)。 例如,Service可以處理網(wǎng)絡(luò)事務(wù)、播放音樂,執(zhí)行文件 I/O 或與內(nèi)容提供程序交互,而所有這一切均可在后臺進(jìn)行。
Service是一個專門在后臺處理長時間任務(wù)的Android組件。
1.Service不是一個多帶帶的進(jìn)程;
2.Service也不是一個多帶帶的線程;
3.Service是一個多帶帶的Android組件,Service運(yùn)行在主線程上,如果想在Service中處理很占時間的操作時,必須在Service中開線程,以降低Activity沒有響應(yīng)的風(fēng)險;
4.Service不提供用戶界面;
它有兩種啟動方式:startService和bindService。
2.用途Service有三個常見用途。
1.功能調(diào)度:Service接收指定的廣播信息,從而進(jìn)一步分析和處理事件,最后修改數(shù)據(jù)、更新界面或者進(jìn)行其他相關(guān)的操作,調(diào)度整個應(yīng)用使其保持正確的狀態(tài)。
2.功能提供:Service并不會接收任何的廣播,只接收指定的廣播提供狀態(tài)數(shù)據(jù),這時需要綁定Service,綁定Service時要管理好Service,一般在Activity的onStop函數(shù)里進(jìn)行解綁unBindService操作。
3.遠(yuǎn)程調(diào)用:定義AIDL服務(wù),跨進(jìn)程調(diào)用Service,先定義一個遠(yuǎn)程調(diào)用接口,然后為該接口提供一個IBinder實(shí)現(xiàn)類,客戶端獲取了遠(yuǎn)程的Service的IBinder對象的代理后,通過該IBinder對象去回調(diào)遠(yuǎn)程Service的屬性或方法。
3.應(yīng)用場景如果某個程序組件需要在運(yùn)行時向用戶呈現(xiàn)界面,或者程序需要與用戶交互,就需要用Activity,否則就應(yīng)該考慮使用Service。
4.Service與Activity對比相似點(diǎn):
1.都是多帶帶的Android組件;
2.都擁有獨(dú)立的生命周期;
3.都是Context的派生類,所以可以調(diào)用Context類定義的如getResources()、getContentResolver()等方法;
4.都擁有自己生命周期回調(diào)方法;
不同點(diǎn):
1.Activity運(yùn)行于前臺有圖形用戶界面,負(fù)責(zé)與用戶交互;Service通常位于后臺運(yùn)行,不需要與用戶交互,也沒有圖形用戶界面。
5.Service的生命周期隨著應(yīng)用程序啟動Service方式不同,Service的生命周期也略有差異,如下圖:
如果應(yīng)用程序通過startService()方法來啟動Service,Service的生命周期如上圖左半部分所示。
通過調(diào)用startService() 方法啟動Service:
當(dāng)其他組件調(diào)用startService()方法時,Service被創(chuàng)建,并且無限期運(yùn)行,其自身必須調(diào)用stopSelf()方法或者其他組件調(diào)用stopService() 方法來停止Service,當(dāng)Service停止時,系統(tǒng)將其銷毀。
如果應(yīng)用程序通過bindService()方法來啟動Service,Service的生命周期如上圖右半部分所示。
通過bindService() 方法啟動Service:
當(dāng)其他組件調(diào)用bindService()方法時,Service被創(chuàng)建。接著客戶端通過IBinder接口與Service通信??蛻舳送ㄟ^unbindService() 方法關(guān)閉連接。多個客戶端能綁定到同一個Service,并且當(dāng)他們都解除綁定時,系統(tǒng)將銷毀Service(Service不需要被停止)
特別說明:當(dāng)Activity調(diào)用bindService()綁定一個已通過startService()啟動的Service時,系統(tǒng)只是把Service內(nèi)部的IBinder對象傳給Activity,并不會把該Service生命周期完全綁定到該Activity,因而當(dāng)Activity調(diào)用unBindService()方法取消與該Service的綁定時,也只是切斷該Activity與Service之間的關(guān)聯(lián),并不能停止該Service組件。要停止該Service組件,還需調(diào)用stopService()方法。
在Service的生命周期里,常用的有:
4個手動調(diào)用的方法
手動調(diào)用方法 | 作用 |
---|---|
startService() | 啟動服務(wù) |
stopService() | 關(guān)閉服務(wù) |
bindService() | 綁定服務(wù) |
unbindService() | 解綁服務(wù) |
5個自動調(diào)用的方法
內(nèi)部自動調(diào)用的方法 | 作用 |
---|---|
onCreate() | 創(chuàng)建服務(wù) |
onStartCommand() | 開始服務(wù) |
onDestroy() | 銷毀服務(wù) |
onBind() | 綁定服務(wù) |
onUnbind() | 解綁服務(wù) |
當(dāng)我們開始使用Service的時候當(dāng)然是啟動一個Service了,啟動Service的方法和啟動Activity很類似,都需要借助Intent來實(shí)現(xiàn),下面我們就通過一個具體的例子來看一下。
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 IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy() executed"); } }
要創(chuàng)建一個這樣的Service,你需要讓該類繼承Service類,然后重寫以下方法:
onCreate()
1.如果service沒被創(chuàng)建過,調(diào)用startService()后會執(zhí)行onCreate()和onStartCommand()方法;
2.如果service已處于運(yùn)行中,調(diào)用startService()不會執(zhí)行onCreate()方法,只執(zhí)行onStartCommand()方法。
也就是說,onCreate()只會在第一次創(chuàng)建service時候調(diào)用,多次執(zhí)行startService()不會重復(fù)調(diào)用onCreate(),此方法適合完成一些初始化工作。
onStartCommand()
如果多次執(zhí)行了Context的startService()方法,那么Service的onStartCommand()方法也會相應(yīng)的多次調(diào)用。onStartCommand()方法很重要,我們在該方法中根據(jù)傳入的Intent參數(shù)進(jìn)行實(shí)際的操作,比如會在此處創(chuàng)建一個線程用于下載數(shù)據(jù)或播放音樂等。
onBind()
Service中的onBind()方法是抽象方法,Service類本身就是抽象類,所以onBind()方法是必須重寫的,即使我們用不到。
onDestroy()
在銷毀的時候會執(zhí)行Service的該方法。
這幾個方法都是回調(diào)方法,且在主線程中執(zhí)行,由Android操作系統(tǒng)在合適的時機(jī)調(diào)用。
注意:每個Service必須在manifest中 通過
...
現(xiàn)在我們通過繼承Service的方式定義了我們自己的MyService類,并且在manifest中聲明了我們的MyService,接下來我們應(yīng)該啟動我們自己的服務(wù)。
第一種方式:我們是通過一個Intent對象,并調(diào)用startService()方法來啟動MyService。
Intent startIntent = new Intent(this, MyService.class); startService(startIntent);
注意:假如我們是通過點(diǎn)擊Button執(zhí)行上面的代碼,那么第一次點(diǎn)擊的時候回執(zhí)行其中的onCreate()跟onStartCommand()方法,但是當(dāng)我們第二次點(diǎn)擊的時候就只會執(zhí)行onStartCommand()方法。
為什么會這樣呢?
這是由于onCreate()方法只會在Service第一次被創(chuàng)建的時候調(diào)用,如果當(dāng)前Service已經(jīng)被創(chuàng)建過了(第一次點(diǎn)擊創(chuàng)建了MyService),不管怎樣調(diào)用startService()方法,onCreate()方法都不會再執(zhí)行。
第二種方式:通過bindService啟動Service。
bindService啟動服務(wù)特點(diǎn):
1.bindService啟動的服務(wù)和調(diào)用者之間是典型的client-server模式。調(diào)用者是client,service則是server端。service只有一個,但綁定到service上面的client可以有一個或很多個。這里所提到的client指的是組件,比如某個Activity。
2.client可以通過IBinder接口獲取Service實(shí)例,從而實(shí)現(xiàn)在client端直接調(diào)用Service中的方法以實(shí)現(xiàn)靈活交互,這在通過startService()方法啟動中是無法實(shí)現(xiàn)的。
3.bindService啟動服務(wù)的生命周期與其綁定的client息息相關(guān)。當(dāng)client銷毀時,client會自動與Service解除綁定(client會有ServiceConnectionLeaked異常,但程序不會崩潰)。當(dāng)然,client也可以明確調(diào)用Context的unbindService()方法與Service解除綁定。當(dāng)沒有任何client與Service綁定時,Service會自行銷毀。
啟動了之后,當(dāng)我們想停止服務(wù)的時候該怎么做呢?
第一種方式:我們也是通過一個Intent對象,并調(diào)用stopService()方法來停止MyService
Intent stopIntent = new Intent(this, MyService.class); stopService(stopIntent);
第二種方式:調(diào)用unbindService(conn)方法來停止MyService
unbindService(ServiceConnection conn)
在上面我們高高興興的啟動了Service了,但是細(xì)心的你可能發(fā)現(xiàn)了,貌似我們僅僅只是啟動了而已,Activity跟Service并沒有多少"交流",下面我們就讓Activity跟Service交流一下。
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 startDownload() { Log.d("TAG", "startDownload() executed"); // 執(zhí)行具體的下載任務(wù) } } }
接下來我們在MainActivity中通過Button來綁定Service和解除綁定
public class MainActivity extends Activity implements OnClickListener { private Button bindService; private Button unbindService; private MyService.MyBinder myBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { myBinder = (MyService.MyBinder) service; myBinder.startDownload(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindService = (Button) findViewById(R.id.bind_service); unbindService = (Button) findViewById(R.id.unbind_service); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bind_service: Intent bindIntent = new Intent(this, MyService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE); break; case R.id.unbind_service: unbindService(connection); break; default: break; } } }
可以看到,這里我們首先創(chuàng)建了一個ServiceConnection的匿名類,在里面重寫了onServiceConnected()方法和onServiceDisconnected()方法,這兩個方法分別會在Activity與Service建立關(guān)聯(lián)和解除關(guān)聯(lián)的時候調(diào)用。在onServiceConnected()方法中,我們又通過 向下轉(zhuǎn)型 得到了MyBinder的實(shí)例,有了這個實(shí)例,Activity和Service之間的關(guān)系就變得非常緊密了?,F(xiàn)在我們可以在Activity中根據(jù)具體的場景來調(diào)用MyBinder中的任何public方法,即實(shí)現(xiàn)了Activity指揮Service干什么Service就去干什么的功能。
當(dāng)然,現(xiàn)在Activity和Service其實(shí)還沒關(guān)聯(lián)起來了呢,這個功能是在Bind Service按鈕的點(diǎn)擊事件里完成的??梢钥吹剑@里我們?nèi)匀皇菢?gòu)建出了一個Intent對象,然后調(diào)用bindService()方法將Activity和Service進(jìn)行綁定。bindService()方法接收三個參數(shù),第一個參數(shù)就是剛剛構(gòu)建出的Intent對象,第二個參數(shù)是前面創(chuàng)建出的ServiceConnection的實(shí)例,第三個參數(shù)是一個標(biāo)志位,這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關(guān)聯(lián)后自動創(chuàng)建Service,這會使得MyService中的onCreate()方法得到執(zhí)行,但onStartCommand()方法不會執(zhí)行(只有當(dāng)我們通過 startService()方法請求啟動服務(wù)時,調(diào)用此方法)。
解除Activity和Service之間的關(guān)聯(lián),調(diào)用
unbindService(connection);
在MyService的內(nèi)部通過stopSelf()方法來銷毀的;
一個Service必須要在既沒有和任何Activity關(guān)聯(lián)又處理停止?fàn)顟B(tài)的時候才會被銷毀;
在Service的onDestroy()方法里去清理掉那些不再使用的資源,防止在Service被銷毀后還會有一些不再使用的對象仍占用著內(nèi)存;
7.IntentServiceIntentService是Service的子類,在介紹IntentService之前,先來了解使用Service時需要注意的兩個問題
Service 不會專門啟動一個線程執(zhí)行耗時操作,所有的操作都是在主線程中進(jìn)行的,以至于容易出現(xiàn)ANR,所以需要手動開啟一個子線程;
Service 不會自動停止,需要調(diào)用stopSelf()方法 或者 是stopService() 方法停止;
使用IntentService不會出現(xiàn)這兩個問題,因為IntentService在開啟Service時,會自動開啟一個新的線程來執(zhí)行它,另外,當(dāng)Service運(yùn)行結(jié)束后,會自動停止。
8.如何保證服務(wù)不會被殺死第一種方式,返回 START_STICKY 或 START_REDELIVER_INTENT
當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,一段時間后內(nèi)存再次空閑時,系統(tǒng)將會嘗試重新創(chuàng)建此Service,一旦創(chuàng)建成功后將回調(diào)onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個狀態(tài)下比較適用于不執(zhí)行命令、但無限期運(yùn)行并等待作業(yè)的媒體播放器或類似的服務(wù)。
/** * 返回 START_STICKY 或 START_REDELIVER_INTENT * @param intent * @param flags * @param startId * @return */ @Override public int onStartCommand(Intent intent, int flags, int startId) { //return super.onStartCommand(intent, flags, startId); return START_STICKY; }
第二種方式,提高service的優(yōu)先權(quán)
結(jié)語?? ???? ?? ???????? ???? ????
Service作為Android的四大組件之一,并且項目開發(fā)過程中一些場景下經(jīng)常被使用到,小伙伴們趕緊上手實(shí)操,把它靈活的運(yùn)用到項目中,結(jié)合上兩期的Activity和BroadcastReceiver實(shí)現(xiàn)有趣的交互吧。
PS:如果還有未看懂的小伙伴,歡迎加入我們的QQ技術(shù)交流群:892271582,里面有各種大神回答小伙伴們遇到的問題哦~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/76161.html
摘要:我們這里就來解讀一下注釋上所描述的返回值的作用與效果相同,主要是為了兼容低版本,但是并不能保證每次都重啟成功。對方法返回不同的返回值導(dǎo)致服務(wù)被殺死的時候自動重啟,這個重啟次數(shù)只能是一次。感謝方法詭異的返回值中類中返回值介紹 showImg(https://segmentfault.com/img/remote/1460000018677403?w=2008&h=1028); 前言 Se...
摘要:四大組件都支持這個屬性。到目前為止,中總共有三種啟動方式。返回值方法有一個的返回值,這個返回值標(biāo)識服務(wù)關(guān)閉后系統(tǒng)的后續(xù)操作。,啟動后的服務(wù)被殺死,不能保證系統(tǒng)一定會重新創(chuàng)建。 1. 簡介 這篇文章會從Service的一些小知識點(diǎn),延伸到Android中幾種常用進(jìn)程間通信方法。 2. 進(jìn)程 ? ? ? ?Service是一種不提供用戶交互頁面但是可以在后臺長時間運(yùn)行的組件,可以通過在An...
閱讀 2978·2021-10-14 09:42
閱讀 1334·2021-09-24 10:32
閱讀 3071·2021-09-23 11:21
閱讀 2921·2021-08-27 13:10
閱讀 3400·2019-08-29 18:41
閱讀 2269·2019-08-29 15:16
閱讀 1304·2019-08-29 13:17
閱讀 970·2019-08-29 11:22