Android Service(服務(wù))淺析

Service概念

Service
是一個可以在后臺執(zhí)行長時間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動亥曹,而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺繼續(xù)運(yùn)行。 此外埠帕,組件可以綁定到服務(wù),以與之進(jìn)行交互玖绿,甚至是執(zhí)行進(jìn)程間通信 (IPC)敛瓷。 例如,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)斑匪、播放音樂呐籽,執(zhí)行文件 I/O 或與內(nèi)容提供程序交互,而所有這一切均可在后臺進(jìn)行蚀瘸。

需要注意的是:

  1. Service 不是線程狡蝶,它運(yùn)行于其托管進(jìn)程的main線程之上(Local or Remote)。
  2. 因為Service仍舊運(yùn)行在main線程上贮勃,如果程序要進(jìn)行某些耗時操作贪惹,則需另開線程,否則就有可能出現(xiàn)主線程阻塞寂嘉,輕則影響用戶體驗奏瞬,重則導(dǎo)致ANR(Application Not Responding)的產(chǎn)生。

Service or Thread?

單從Service的概念來看泉孩,似乎Service可以做的所有工作Thread也能做硼端,那么Service和Thread到底該如何選擇呢?
簡單的說可以通過以下兩個原則進(jìn)行選擇:

  1. 如果在用戶與應(yīng)用程序進(jìn)行界面交互時需要在主線程之外執(zhí)行后臺工作寓搬,則可以選擇使用線程(比如:處于Activity運(yùn)行狀態(tài)珍昨,需要加載一些大圖片用于界面顯示,頁面BGM的播放等)
  2. 如果希望在Activity不可見時,應(yīng)用程序仍舊可以在后臺執(zhí)行一些工作則最好使用Service來實現(xiàn)(比如:用戶在Activity顯示狀態(tài)時開啟了網(wǎng)絡(luò)下載的工作并且希望在應(yīng)用程序后臺時下載工作仍然進(jìn)行)曼尊。

可能有些人會想:使用線程也可以在應(yīng)用程序后臺時執(zhí)行下載工作啊酬诀。
針對后臺下載,現(xiàn)在來設(shè)想一下以下情況:
在Activity中開啟下載線程之后骆撇,由于某些情況該Activity被銷毀或重啟了(配置發(fā)生改變瞒御、界面不可見后內(nèi)存過低被系統(tǒng)回收),此時我們將不在持有該下載線程的引用神郊!如果用戶此時想要暫停下載肴裙,我們是沒有辦法對前面創(chuàng)建的下載線程執(zhí)行該操作的!而且也不利于系統(tǒng)資源的管理涌乳。
使用Service還有其他幾個好處:

  • 如果在應(yīng)用程序中啟動了服務(wù)蜻懦,則應(yīng)用程序的優(yōu)先級將被提高。僅當(dāng)內(nèi)存過低且必須回收系統(tǒng)資源時進(jìn)程才會被殺死夕晓。
  • 如果服務(wù)被系統(tǒng)殺死宛乃,我們可以通過指定onStartCommand的返回值的方式來促使系統(tǒng)在資源可用時重啟服務(wù)。

Service的兩種用法的不同

  • 首先我們需要自定義一個Service類蒸辆,代碼如下
public class MyService extends Service {
    public MyService() {
    }
    /**
     * 該方法是Service類中的唯一一個abstract方法征炼,必須重寫
     * 當(dāng)另一個組件想通過調(diào)用 bindService() 與服務(wù)綁定(例如執(zhí)行 RPC)時,系統(tǒng)將調(diào)用此方法躬贡。
     * 在此方法的實現(xiàn)中谆奥,您必須通過返回 IBinder 提供一個接口,供客戶端用來與服務(wù)進(jìn)行通信拂玻。
     * 請務(wù)必實現(xiàn)此方法酸些,但如果您并不希望允許綁定,則應(yīng)返回 null檐蚜。
     */
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //系統(tǒng)默認(rèn)返回START_STICKY
        //當(dāng)服務(wù)被系統(tǒng)kill之后執(zhí)行重啟服務(wù)的操作
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
  • onCreate():當(dāng)服務(wù)首次被使用時魄懂,該方法將會首先被調(diào)用。如果服務(wù)已經(jīng)處于使用狀態(tài)則該方法不會被調(diào)用熬甚。

  • onStartCommand():當(dāng)其他組件通過startService()啟動服務(wù)時逢渔,該方法將被調(diào)用(onCreate()之后)∠缋ǎ可以通過該方法的返回值控制Service在被系統(tǒng)kill之后的重啟行為:
    START_NOT_STICKY:當(dāng)Service被系統(tǒng)kill之后肃廓,將不會執(zhí)行重啟操作。
    START_STICKY:當(dāng)Service被系統(tǒng)kill之后诲泌,將會通過調(diào)用onStartCommand()來執(zhí)行重啟操作盲赊。但是傳遞給該方法的Intent將是一個空Intent。適用于不執(zhí)行命令敷扫、但無限期運(yùn)行并等待作業(yè)的媒體播放器(或類似服務(wù))哀蘑。
    START_REDELIVER_INTENT:當(dāng)Service被系統(tǒng)kill之后诚卸,將會通過調(diào)用onStartCommand()來執(zhí)行重啟操作。傳遞給該方法的Intent是最后一個傳遞給服務(wù)的Intent.這適用于主動執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)绘迁。

  • onBind():當(dāng)其他組件通過bindService的方式綁定服務(wù)時合溺,該方法將被調(diào)用。需要返回一個借口用來與其他組件之間進(jìn)行通信缀台。該方法必須重寫棠赛,如果不希望Service通過綁定的形式被使用則返回null。

  • onDestroy():當(dāng)服務(wù)被銷毀時將調(diào)用此方法膛腐。

  • 啟動服務(wù):如果僅通過該方式使用服務(wù)睛约,則在希望銷毀服務(wù)時只需調(diào)用一次stopService()或stopSelf()(無論調(diào)用多少次startService),服務(wù)自動進(jìn)入銷毀流程哲身。

  • 綁定服務(wù):如果僅通過該方式使用服務(wù)辩涝,則在希望銷毀服務(wù)時必須調(diào)用多次unBindService()(與調(diào)用bindService()次數(shù)相對應(yīng))之后,服務(wù)才會進(jìn)入銷毀流程勘天。

  • 啟動+綁定:當(dāng)通過該方式使用服務(wù)時怔揩,不能單純的通過stop和unBind的方式停止服務(wù)。必須同時滿足Service stop并且沒有和任何組件bind的條件才會進(jìn)入銷毀流程误辑。

通過bindService使用服務(wù)的簡單實現(xiàn)代碼:

MainActivity.java

package com.example.myservice;

import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private MyService.Download mDownload;
    private ServiceConnection mConnection = new ServiceConnection() {
        //iBinder與onBind()返回值對應(yīng)
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mDownload = (MyService.Download)iBinder;
            mDownload.startDownload();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mDownload.stopDownload();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Service.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(mConnection);
        super.onDestroy();
    }
}

MyService.java

package com.example.myservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

public class MyService extends Service {
    private final String TAG = "MyService";
    private Download mDownload = new Download();
    public MyService() {
    }

    class Download extends Binder {

        private int mProgress = 0;
        private boolean isRun;

        private Thread downThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (mProgress < 100 && isRun) {
                    SystemClock.sleep(50);
                    mProgress++;
                    Log.d(TAG,"down progress is:"+ mProgress);
                }
            }
        });

        public void startDownload() {
            isRun = true;
            downThread.start();
        }

        public void stopDownload(){
            isRun = false;
        }
        public int getDownloadProgress(){
            return mProgress;
        }
    }
    /**
     * 該方法是Service類中的唯一一個abstract方法沧踏,必須重寫
     * 當(dāng)另一個組件想通過調(diào)用 bindService() 與服務(wù)綁定(例如執(zhí)行 RPC)時,系統(tǒng)將調(diào)用此方法巾钉。
     * 在此方法的實現(xiàn)中,您必須通過返回 IBinder 提供一個接口秘案,供客戶端用來與服務(wù)進(jìn)行通信砰苍。
     * 請務(wù)必實現(xiàn)此方法,但如果您并不希望允許綁定阱高,則應(yīng)返回 null赚导。
     */
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mDownload;
    }
    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate");
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //系統(tǒng)默認(rèn)返回START_STICKY
        //當(dāng)服務(wù)被系統(tǒng)kill之后執(zhí)行重啟服務(wù)的操作
        Log.d(TAG, "onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy()");
        super.onDestroy();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赤惊,隨后出現(xiàn)的幾起案子吼旧,更是在濱河造成了極大的恐慌,老刑警劉巖未舟,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件圈暗,死亡現(xiàn)場離奇詭異,居然都是意外死亡裕膀,警方通過查閱死者的電腦和手機(jī)员串,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昼扛,“玉大人寸齐,你說我怎么就攤上這事。” “怎么了渺鹦?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵扰法,是天一觀的道長。 經(jīng)常有香客問我毅厚,道長迹恐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任卧斟,我火速辦了婚禮殴边,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘珍语。我一直安慰自己锤岸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布板乙。 她就那樣靜靜地躺著是偷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪募逞。 梳的紋絲不亂的頭發(fā)上蛋铆,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機(jī)與錄音放接,去河邊找鬼刺啦。 笑死,一個胖子當(dāng)著我的面吹牛纠脾,可吹牛的內(nèi)容都是我干的玛瘸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼苟蹈,長吁一口氣:“原來是場噩夢啊……” “哼糊渊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慧脱,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤渺绒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后菱鸥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宗兼,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年采缚,在試婚紗的時候發(fā)現(xiàn)自己被綠了针炉。 大學(xué)時的朋友給我發(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
  • 我被黑心中介騙來泰國打工情连, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留叽粹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓蒙具,卻偏偏與公主長得像球榆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子禁筏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

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

  • 前言:本文所寫的是博主的個人見解,如有錯誤或者不恰當(dāng)之處衡招,歡迎私信博主篱昔,加以改正!原文鏈接始腾,demo鏈接 Serv...
    PassersHowe閱讀 1,421評論 0 5
  • [文章內(nèi)容來自Developers] Service是一個可以在后臺執(zhí)行長時間運(yùn)行操作而不提供用戶界面的應(yīng)用組件州刽。...
    岳小川閱讀 869評論 0 7
  • 上篇我們講解了Android中的5中等級的進(jìn)程,分別是:前臺進(jìn)程浪箭、可見進(jìn)程穗椅、服務(wù)進(jìn)程、后臺進(jìn)程奶栖、空進(jìn)程匹表。系統(tǒng)會按照...
    徐愛卿閱讀 3,864評論 6 33
  • 羅輯思維袍镀,吳軍默蚌,硅谷來信 20161030,53/70苇羡,晚間打卡 讀者問題:小公司戰(zhàn)勝大公司绸吸,就像螞蟻戰(zhàn)勝了大象。...
    諸慧的身心園地閱讀 243評論 0 0
  • 今天是個糟心的周末设江,甚至是黑色的锦茁! 家里的微信群一般都是很平靜,偶爾彈出來幾條語音就沒了下文叉存,今天也是如此码俩,只是叔...
    花樣創(chuàng)意閱讀 267評論 0 0