Android:Service詳解

這篇文章主要是講解Service

前言:Service非常適用于去執(zhí)行那些不需要和用戶(hù)交互而且還要長(zhǎng)期運(yùn)行在后臺(tái)的任務(wù)。Service默認(rèn)線程為UI線程,不要在Service中執(zhí)行耗時(shí)的操作,除非你在Service中創(chuàng)建了子線程來(lái)完成耗時(shí)操作.
Service的運(yùn)行不依賴(lài)于任何用戶(hù)界面,即使程序被切換到后臺(tái)或者用戶(hù)打開(kāi)另一個(gè)應(yīng)用程序,Service仍然能夠保持正常運(yùn)行,這也正是Service的使用場(chǎng)景。當(dāng)某個(gè)應(yīng)用程序進(jìn)程被殺掉時(shí),所有依賴(lài)于該進(jìn)程的Service也會(huì)停止運(yùn)行.

一、Service的基本用法

普通的Service的生命周期很簡(jiǎn)單,分別為onCreate、onStartCommand、onDestroy這三個(gè)。當(dāng)我們startService()的時(shí)候,首次創(chuàng)建Service會(huì)回調(diào)onCreate()方法,然后回調(diào)onStartCommand()方法,再次startService()的時(shí)候,就只會(huì)執(zhí)行onStartCommand()。服務(wù)一旦開(kāi)啟后,我們就需要通過(guò)stopService()方法或者stopSelf()方法關(guān)閉服務(wù),這時(shí)就會(huì)回調(diào)onDestroy()

  • 創(chuàng)建服務(wù)類(lèi)

創(chuàng)建一個(gè)服務(wù)非常簡(jiǎn)單,只要繼承Service,并實(shí)現(xiàn)onBind()方法

public class BackGroupService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("Service","onBind");
        return null;
    }

    @Override
    public void onCreate() {
        Log.e("Service","onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("Service","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.e("Service","onDestroy");
        super.onDestroy();
    }
}
  • 配置AndroidManifest
    Service也是四大組件之一,所以必須在AndroidManifest中配置
    <service android:name=".BackGroupService" />
  • 啟動(dòng)服務(wù)和停止服務(wù)
    我們通過(guò)兩個(gè)按鈕分別演示啟動(dòng)服務(wù)和停止服務(wù),通過(guò)startService()開(kāi)啟服務(wù),通過(guò)stopService()停止服務(wù)
Intent startServiceIntent = new Intent(this, BackGroupService.class);
startService.setOnClickListener((v)-> {
                //啟動(dòng)服務(wù)
                startService(startServiceIntent );
        });
        stopService.setOnClickListener((v)-> {
                //停止服務(wù)
                stopService(startServiceIntent);
        });

運(yùn)行程序后,我們點(diǎn)擊開(kāi)始服務(wù),然后關(guān)閉服務(wù)。我們以Log信息來(lái)驗(yàn)證普通Service的生命周期:onCreate->onStartCommand->onDestroy
當(dāng)你開(kāi)啟服務(wù)后,還有一種方法可以關(guān)閉服務(wù),在設(shè)置中,通過(guò)應(yīng)用->找到自己應(yīng)用->停止

二、Service和Activity進(jìn)行通信

Service和Activity進(jìn)行通信指前臺(tái)頁(yè)面(Activity)可以調(diào)用后臺(tái)服務(wù)的方法,實(shí)現(xiàn)步驟是和普通服務(wù)實(shí)現(xiàn)步驟是一樣的,區(qū)別在于啟動(dòng)的方式和獲得Service的代理對(duì)象

  • 創(chuàng)建服務(wù)類(lèi)

這里和普通Service不同,在onBind中返回一個(gè)Binder 對(duì)象,Activity可以獲取該Binder 對(duì)象從而執(zhí)行后臺(tái)服務(wù)的方法.

class MyBind extends Binder {
    public void startDownload() {
        Log.d("Service", "開(kāi)始下載");
        // 執(zhí)行具體的下載任務(wù)
    }
}
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("Service", "onBind");
        return new MyBind(); //這里返回服務(wù)代理對(duì)象
    }
    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("Service", "onUnbind");
        return super.onUnbind(intent);
    }
  • 綁定服務(wù)和解除綁定服務(wù)
    我們通過(guò)兩個(gè)按鈕分別演示綁定服務(wù)和解除綁定服務(wù),通過(guò)bindService()開(kāi)啟服務(wù),通過(guò)unbindService()停止服務(wù)
bindService.setOnClickListener((view)-> {
                bindService(startServiceIntent,serviceConnection,BIND_AUTO_CREATE);
        });
unbindService.setOnClickListener((view->) {
         unbindService(serviceConnection);
        });
  }
    /**
     * 創(chuàng)建ServiceConnection
     */
    final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //拿到后臺(tái)服務(wù)代理對(duì)象
            final MyBind myBind = (MyBind) iBinder;
            myBind.startDownload();
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

這里和startService的區(qū)別在于多了一個(gè)ServiceConnection對(duì)象,該對(duì)象是用戶(hù)綁定后臺(tái)服務(wù)后,可獲取后臺(tái)服務(wù)代理對(duì)象的回調(diào),我們可以通過(guò)該回調(diào),拿到后臺(tái)服務(wù)的代理對(duì)象,并調(diào)用后臺(tái)服務(wù)定義的方法,也就實(shí)現(xiàn)了后臺(tái)服務(wù)和前臺(tái)的交互

  • 運(yùn)行代碼
    運(yùn)行程序后,我們點(diǎn)擊綁定服務(wù),然后一段時(shí)間后解除綁定服務(wù)。我們以Log信息來(lái)驗(yàn)證Service的生命周期:onCreate->onBind->onUnBind->onDestroy,其中onbind開(kāi)啟服務(wù)重復(fù)開(kāi)啟不會(huì)執(zhí)行任何方法,其中也可以看到我們調(diào)用后臺(tái)服務(wù)的方法開(kāi)始下載了....


  • 混合性交互的后臺(tái)服務(wù)
    如果我們既點(diǎn)擊了Start Service按鈕,又點(diǎn)擊了Bind Service按鈕會(huì)怎么樣呢?這個(gè)時(shí)候你會(huì)發(fā)現(xiàn),不管你是單獨(dú)點(diǎn)擊Stop Service按鈕還是Unbind Service按鈕,Service都不會(huì)被銷(xiāo)毀,必要將兩個(gè)按鈕都點(diǎn)擊一下,Service才會(huì)被銷(xiāo)毀。也就是說(shuō),點(diǎn)擊Stop Service按鈕只會(huì)讓Service停止,點(diǎn)擊Unbind Service按鈕只會(huì)讓Service和Activity解除關(guān)聯(lián),一個(gè)Service必須要在既沒(méi)有和任何Activity關(guān)聯(lián)又處理停止?fàn)顟B(tài)的時(shí)候才會(huì)被銷(xiāo)毀。


三、Service和Thread的關(guān)系
Service和Thread到底有什么關(guān)系呢?什么時(shí)候應(yīng)該用Service,什么時(shí)候又應(yīng)該用Thread?
答案是Service和Thread之間沒(méi)有任何關(guān)系!

之所以有不少人會(huì)把它們聯(lián)系起來(lái),主要就是因?yàn)镾ervice的后臺(tái)概念。Thread我們大家都知道,是用于開(kāi)啟一個(gè)子線程,在這里去執(zhí)行一些耗時(shí)操作就不會(huì)阻塞主線程的運(yùn)行。而Service我們最初理解的時(shí)候,總會(huì)覺(jué)得它是用來(lái)處理一些后臺(tái)任務(wù)的,一些比較耗時(shí)的操作也可以放在這里運(yùn)行,這就會(huì)讓人產(chǎn)生混淆了。但是Service其實(shí)就是運(yùn)行在主線程里的,那要Service又有何用呢?其實(shí)大家不要把后臺(tái)和子線程聯(lián)系在一起就行了,這是兩個(gè)完全不同的概念。Android的后臺(tái)就是指,它的運(yùn)行是完全不依賴(lài)UI的。即使Activity被銷(xiāo)毀,或者程序被關(guān)閉,只要進(jìn)程還在,Service就可以繼續(xù)運(yùn)行。比如說(shuō)一些應(yīng)用程序,始終需要與服務(wù)器之間始終保持著心跳連接,就可以使用Service來(lái)實(shí)現(xiàn)。在Service中再創(chuàng)建一個(gè)子線程,然后在這里去處理耗時(shí)邏輯就沒(méi)問(wèn)題了。既然在Service里也要?jiǎng)?chuàng)建一個(gè)子線程,那為什么不直接在Activity里創(chuàng)建呢?這是因?yàn)锳ctivity很難對(duì)Thread進(jìn)行控制,當(dāng)Activity被銷(xiāo)毀之后,就沒(méi)有任何其它的辦法可以再重新獲取到之前創(chuàng)建的子線程的實(shí)例。而且在一個(gè)Activity中創(chuàng)建的子線程,另一個(gè)Activity無(wú)法對(duì)其進(jìn)行操作。但是Service就不同了,所有的Activity都可以與Service進(jìn)行關(guān)聯(lián),然后可以很方便地操作其中的方法,即使Activity被銷(xiāo)毀了,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中Binder的實(shí)例。因此,使用Service來(lái)處理后臺(tái)任務(wù),Activity就可以放心地finish,完全不需要擔(dān)心無(wú)法對(duì)后臺(tái)任務(wù)進(jìn)行控制的情況。

四、前臺(tái)服務(wù)
Service幾乎都是在后臺(tái)運(yùn)行的,一直以來(lái)它都是默默地做著辛苦的工作。但是Service的系統(tǒng)優(yōu)先級(jí)還是比較低的,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足情況時(shí),就有可能會(huì)回收掉正在后臺(tái)運(yùn)行的Service。如果你希望Service可以一直保持運(yùn)行狀態(tài),而不會(huì)由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥?,就可以考慮使用前臺(tái)Service。前臺(tái)Service和普通Service最大的區(qū)別就在于,它會(huì)一直有一個(gè)正在運(yùn)行的圖標(biāo)在系統(tǒng)的狀態(tài)欄顯示,下拉狀態(tài)欄后可以看到更加詳細(xì)的信息,非常類(lèi)似于通知的效果。當(dāng)然有時(shí)候你也可能不僅僅是為了防止Service被回收才使用前臺(tái)Service,有些項(xiàng)目由于特殊的需求會(huì)要求必須使用前臺(tái)Service.

  • 創(chuàng)建服務(wù)類(lèi)
    前臺(tái)服務(wù)創(chuàng)建很簡(jiǎn)單,其實(shí)就在Service的基礎(chǔ)上創(chuàng)建一個(gè)Notification,然后使用Service的startForeground()方法即可啟動(dòng)為前臺(tái)服務(wù)
private void showNotification() {
        final Notification.Builder mBuilder = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("前臺(tái)服務(wù)")
                .setContentText("我是前臺(tái)服務(wù)");
        final Intent intent = new Intent(this, MainActivity.class);
        //創(chuàng)建任務(wù)棧Builder
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(intent);
        PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
        //設(shè)置跳轉(zhuǎn)Intent到通知中
        mBuilder.setContentIntent(pendingIntent);
        //獲取通知服務(wù)
        NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        //構(gòu)建通知
        Notification notification = mBuilder.build();
        //顯示通知
        nm.notify(0, notification);
        //啟動(dòng)為前臺(tái)服務(wù)
        startForeground(0, notification);
    }
  • 配置服務(wù)
    <service android:name=".ForegroundService" />
  • 啟動(dòng)和結(jié)束服務(wù)
    現(xiàn)在重新運(yùn)行一下程序,并點(diǎn)擊Start Service或Bind Service按鈕,F(xiàn)oregroundService就會(huì)以前臺(tái)Service的模式啟動(dòng)了,并且在系統(tǒng)狀態(tài)欄會(huì)彈出一個(gè)通欄圖標(biāo),下拉狀態(tài)欄后可以看到通知的詳細(xì)內(nèi)容,如下圖所示。


五、IntentService
IntentService是專(zhuān)門(mén)用來(lái)解決Service中不能執(zhí)行耗時(shí)操作這一問(wèn)題的,創(chuàng)建一個(gè)IntentService也很簡(jiǎn)單,只要繼承IntentService并覆寫(xiě)onHandlerIntent函數(shù),在該函數(shù)中就可以執(zhí)行耗時(shí)操作了,執(zhí)行完耗時(shí)操作后自動(dòng)結(jié)束服務(wù).

public class TheIntentService extends IntentService {

    public TheIntentService() {
        super("TheIntentService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.e("IntentService", "耗時(shí)前");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("IntentService", "耗時(shí)后");
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容