Service的使用

不怕跌倒融求,所以飛翔

本文講解內(nèi)容:

  • Service的簡單使用
    • 普通Service
    • IntentService
  • Service的綁定操作
  • Service的生命周期
  • 前臺Service的使用
  • Android通知欄的使用

1.Service的簡單使用

1.1普通Service的簡單使用

后臺服務的優(yōu)先級是很低的,當系統(tǒng)內(nèi)存不足的時候就會被回收.

  • 創(chuàng)建Service
  • 重寫相應的方法
  • 啟動/關閉服務

1.1.1 創(chuàng)建服務

創(chuàng)建服務的方法就不寫了,這里主要說 明一下AndroidManifest中的屬性

  • android:name Service的類名稱
  • android:label Service的名字
  • android:icon Service的圖標
  • android:enabled 是否可以被系統(tǒng)實例化,默認是true 因為父標簽也有enable屬性,所以必須兩個都為true的情況下服務才能被激活,否則不會被激活.
  • android:exported 代表是否能被其他應用隱式調(diào)用,由inter-filter決定,如果為false的情況下,即便你匹配了inter-filter也無法隱式調(diào)用
  • android:process 是否需要在單獨的進程中運行,當設置為android:process = ":remote"時,代表Service在單獨的進程中運行.這里注意":"很重要,它的意思是要在當前進程名稱前面附加上當前的包名,所以"remote"和":remote"不是同一個意思,前者的進程名稱為:remote,而后者的進程名稱為: App-packageName:remote.
  • android:permission 是權限聲明
  • android:isolatedProcess 設置true意味著服務會在一個特殊的進程下運行,這個進程與系統(tǒng)其他進程分開且沒有自己的權限.與其通信的唯一途徑就是通過服務的API(bind and start)

1.1.2重寫相應的方法

public class GeneralService extends Service {
    private String TAG = GeneralService.class.getSimpleName();

    public GeneralService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        /*這個是綁定Binder的相應的方法,
          *這個服務中先不去考慮
          */
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        /*
        * 創(chuàng)建服務的時候調(diào)的回調(diào)
        * 這個方法只有在創(chuàng)建Service的時候執(zhí)行一次
        */
        Log.e(TAG, "服務創(chuàng)建了");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /*
        * 具體執(zhí)行邏輯的時候的方法
        * 1.這里有一點問題說明一下,有的時候你創(chuàng)建相應的服務了,但是由于后臺資源不足,服務被銷毀了
        * 這個時候,在執(zhí)行的時候就會存在相應intent為空的情況,當你遇到這個情況的時候,只要返回相應的標識就可以了
        *  return Service.START_REDELIVER_INTENT;就能保證服務再次啟動的時候intent不為空了
        * 2.這個方法每次調(diào)用相應的startService都會去執(zhí)行
        */
        Log.e(TAG, "服務正在執(zhí)行");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        /*
        * 銷毀服務的回調(diào)
        * 這個方法只有在銷毀Service的時候執(zhí)行一次
        */
        Log.e(TAG, "服務銷毀了");
    }
}

1.1.3啟動/關閉服務

  • 開啟服務
        Intent intent = new Intent(this, GeneralService.class);
        startService(intent);
    
  • 關閉服務
        Intent intent = new Intent(this, GeneralService.class);
        stopService(intent);
    

1.1.4這里著重介紹一下相應得方法

  • onCreate 服務創(chuàng)建的時候回調(diào)的方法
  • onBind 綁定服務的時候調(diào)用的方法,后面將服務綁定的時候講解
  • onStartCommand 執(zhí)行邏輯的方法
  • onDestory 服務關閉時候的回調(diào)方法

相應的執(zhí)行邏輯:

  1. 正常的生命周期邏輯(第一次啟動)
    構造方法()->onCreate()->onStartCommand()->onDestory();
  2. 當Service存在的情況下再次啟動
    onStartCommand()

也就是說如果多次點擊啟動,onCreate()不會多次執(zhí)行,只有Service銷毀的時候再次啟動的時候才會執(zhí)行相應的onCreat()方法,簡單理解就是onCreat()方法只有在創(chuàng)建的時候執(zhí)行一次!

1.2IntentService的簡單使用

使用上和上面的內(nèi)容沒有什么出入,只是繼承的方法和內(nèi)部相應的實現(xiàn)有點變化,但是變化不是很大,這里就貼一下相應的內(nèi)容,不去做相應的具體講解了,只要記住這個Service能自己調(diào)用相應的onDestory()就可以了.

public class IntentService extends android.app.IntentService {
    private String TAG = IntentService.class.getSimpleName();

    public IntentService() {
        super("IntentService");
        /*調(diào)用父類的構造方法,這里面?zhèn)魅氲拿质枪ぷ骶€程的名稱,所以這個名稱你可以隨便傳*/
        Log.e(TAG, "服務有名字了");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "服務創(chuàng)建了");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        /*
         * 在我的理解,這個工作線程只會有一個,因為里面維護了一個相應的Handler
         * 每次的耗時操作都會以相應的隊列的方式在IntentService中一次執(zhí)行
         * 每次開啟服務的時候都會走這個方法,但是我調(diào)用相應的Stop無法停止相應的服務
         * 這個還有待于研究,因為子停止,或許不需要停止的相應的方法吧(反正相應的停止的方法是不好使的)
         */
        for (int i = 0; i < 100; i++) {
            Log.e(TAG, "服務正在執(zhí)行" + i);
        }
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        /*這個方法實在o'nHandleIntent之前進行執(zhí)行
          *所以這里可以初始化一些相應的內(nèi)容
          */
        Log.e(TAG, "onStartCommand: 執(zhí)行了");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        /*這個方法會在相應的onHandleIntent執(zhí)行完成的時候回調(diào)*/
        Log.e(TAG, "服務銷毀了");
    }
}

相應的啟動方法類似.

但是這里要注意幾個問題:

  1. 當你startService的時候,即使你調(diào)用相應的stopService也不會讓Service停止下來
  2. 這個服務不存在相應的stopService的方法了

剩下的基本上注釋都有.

2.綁定服務的方法

  • 簡單的介紹一下為什么要綁定服務

你可能會發(fā)現(xiàn),上面的方法只是啟動了服務,但是其實Service和Activity其實根本沒有什么關聯(lián),在Activity也沒有辦法去控制Service里面的執(zhí)行內(nèi)容,也就是Service脫離了相應的Activity,只是通過Activity啟動而已,這個不是我們想看到的,所以才有相應的綁定方法來控制Service.

2.1 綁定服務的寫法

上面在開啟服務的時候,不知道大家有沒有注意到一個細節(jié)在onBind()方法中我們返回的是空,為什么這里返回的是空呢???其實這個就是綁定服務所要必須的內(nèi)容.下面我們開始實現(xiàn)簡單的內(nèi)容吧!

2.1.1創(chuàng)建相應的Binder對象

    class MyBinder extends Binder {
        public void startBinder() {
            Log.e(TAG, "startBinder: ");
        }

        public void stopBinder() {
            Log.e(TAG, "stopBinder: ");
        }
    }

這里面的方法你可以隨便的寫,想要什么寫什么!!!

2.1.2在相應的Service中創(chuàng)建相應的對象,并在Binder()中返回

    private MyBinder mMyBinder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return mMyBinder;
    }

2.1.3啟動相應的Service

這個也是這里的重點問題,涉及到一個ServiceConnection

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            /*這個方法會在相應的創(chuàng)建的時候進行調(diào)用*/
            Log.e(TAG, "onServiceConnected:  連接創(chuàng)建的時候調(diào)用");
            //向下轉型從而調(diào)用相應的方法
            BindService.MyBinder binder = (BindService.MyBinder) service;
            binder.bindService();
     }

        @Override
        public void onServiceDisconnected(ComponentName name) {
           /*這個方法是在Service丟失的情況下才被調(diào)用
            * 或者在Service被殺死的視乎調(diào)用*/
        }
    };

說明一下上面兩個回調(diào)方法:

  • onServiceConnected 系統(tǒng)調(diào)用這個方法來傳送在Service的onBind中返回的IBinder
  • onServiceDisconnected 在Service的鏈接意外丟失的時候調(diào)用這個方法,比如當Service崩潰了或者被越塔強殺了的時候會調(diào)用這個方法,但是注意當解除綁定的時候不會調(diào)用這個方法.
  • 還有一點說明一下:startBinder()這個方法是你自己的方法,也就是說,在這里你就可以控制Service了
     //綁定
        Intent intent = new Intent(this, BindService.class);
        /*參數(shù)三有必要說明下:
         *BIND_AUTO_CREATE 這個方法是創(chuàng)建關聯(lián)后自動創(chuàng)建Service,會使得相應Service中的onCreate()方法的到執(zhí)行
         * 但相應的onStartCommand()不會被執(zhí)行
         */
        bindService(intent, mConnection, BIND_AUTO_CREATE);
   
     //解綁
        unbindService(mConnection);

2.1.3BindService的生命周期

構造方法->oncreate()->onBind()->onServiceConnected()
當你再次點擊的時候不會調(diào)用相應的啟動的流程了,除非你調(diào)用unBind()方法進行相應的取消否則不會去創(chuàng)建的,這里只是創(chuàng)建了連接,讓Activity持有了相應的Service可以使用內(nèi)部的相應方法了!

3.Service的聲明周期

  • 當你調(diào)用startService()的時候生命周期是這樣的:
    onCreate() -> onStartCommand()
    這里注意,要是之前你啟動過這個service的話那么onCreate()不會多次調(diào)用,除非你調(diào)用了** stopService(mIntent);**結束了這個Service否則不會在走onCreate();也就是說生命周期中onCreate()只會執(zhí)行一次;
  • 當你調(diào)用stopService()的時候生命周期是這樣的:
    onDestroy()
  • 當你調(diào)用bindService的時候和上面的生命周期類似,這里只是建立了一個持久連接.別無其他.
  • boolean onUnBind(Intent intent) 當該Service上綁定得所有客戶端都斷開連接得時候回調(diào)

這里有一個問題是你需要注意的,如果你想在onStartCommand()想結束Service的話,直接調(diào)用stopSelf()方法就可以了

3.1幾種特殊情況下的生命周期問題

  • 當一個Service既被調(diào)用了bindService()又調(diào)用了startService(),這種情況下你如果想要關閉服務的話,必須兩種服務的結束方法都調(diào)用才能結束當前的服務.也就是stopService()和unBindService()方法同時執(zhí)行,這樣Service才會走onDestroy()方法.

4.一些服務的特殊使用方法

開機啟動服務(其實這個思路很簡單,監(jiān)聽開機的廣播,然后啟動你的服務就可以實現(xiàn)了),下面直接上代碼:

  • 廣播的代碼:
public class BootBroadcastReceiver extends BroadcastReceiver {
    private static final String mBootAction = "android.intent.action.BOOT_COMPLETED";
    private static final String mShutDownAction = "android.intent.action.ACTION_SHUTDOWN";
    private static final String TAG = BootBroadcastReceiver.class.getSimpleName();
    private Intent mServiceIntent;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null) return;
        if (intent.getAction().equals(mBootAction)) {
            Log.e(TAG, "onReceive: 監(jiān)聽到開機廣播了");

            /*這里啟動服務*/
            mServiceIntent = new Intent(context, MyService.class);
            mServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startService(mServiceIntent);

        } else if (intent.getAction().equals(mShutDownAction)) {
            Log.e(TAG, "onReceive: 監(jiān)聽到關機廣播了");
            if (mServiceIntent != null) {
                /*這里關閉服務*/
                context.stopService(mServiceIntent);
            }
        }
    }
}
  • 廣播在清單文件中注冊的代碼
        <receiver
            android:name=".BootBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <!--開機廣播-->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <!--關機廣播-->
            <intent-filter>
                <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

其實上面的內(nèi)容加起來就可以啟動相應的廣播了,但是一定要注意一點就是監(jiān)聽開機廣播的時候涉及到權限的問題

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

這個問題千萬別忘了...

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市算撮,隨后出現(xiàn)的幾起案子生宛,更是在濱河造成了極大的恐慌,老刑警劉巖肮柜,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陷舅,死亡現(xiàn)場離奇詭異,居然都是意外死亡审洞,警方通過查閱死者的電腦和手機莱睁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芒澜,“玉大人仰剿,你說我怎么就攤上這事〕栈蓿” “怎么了南吮?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長誊酌。 經(jīng)常有香客問我部凑,道長,這世上最難降的妖魔是什么术辐? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任砚尽,我火速辦了婚禮,結果婚禮上辉词,老公的妹妹穿的比我還像新娘必孤。我一直安慰自己,他們只是感情好瑞躺,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布敷搪。 她就那樣靜靜地躺著,像睡著了一般幢哨。 火紅的嫁衣襯著肌膚如雪赡勘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天捞镰,我揣著相機與錄音闸与,去河邊找鬼毙替。 笑死,一個胖子當著我的面吹牛践樱,可吹牛的內(nèi)容都是我干的厂画。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼拷邢,長吁一口氣:“原來是場噩夢啊……” “哼袱院!你這毒婦竟也來了?” 一聲冷哼從身側響起瞭稼,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤忽洛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后环肘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欲虚,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年廷臼,在試婚紗的時候發(fā)現(xiàn)自己被綠了苍在。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绝页。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡荠商,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出续誉,到底是詐尸還是另有隱情莱没,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布酷鸦,位于F島的核電站饰躲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏臼隔。R本人自食惡果不足惜嘹裂,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摔握。 院中可真熱鬧寄狼,春花似錦、人聲如沸氨淌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盛正。三九已至删咱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豪筝,已是汗流浹背痰滋。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工摘能, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敲街。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓徊哑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親聪富。 傳聞我的和親對象是個殘疾皇子莺丑,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容