為什么bindService需要傳遞ServiceConnection?

service的異步創(chuàng)建


做過(guò)Android開發(fā)的基本都清楚求类,當(dāng)進(jìn)行bindService調(diào)用的時(shí)候霜大,需要傳遞一個(gè)ServiceConnection癞谒,當(dāng)service創(chuàng)建完畢之后啊掏,會(huì)回調(diào)ServiceConnection的方法來(lái)通知調(diào)用方梗搅,也就是說(shuō)bindService是異步的禾唁。

根本原因在于service的onCreate/onStartCommand/onStart生命周期相關(guān)的方法總是在 主線程 上執(zhí)行的,如果bindService在主線程上阻塞的話无切,這個(gè)時(shí)候荡短,service就無(wú)法執(zhí)行上述生命周期相關(guān)的方法,完成初始化工作订雾。既然不能阻塞肢预,只好通過(guò)ServiceConnection來(lái)回調(diào)通知了。

進(jìn)一步而言洼哎,bindService之后烫映,需要立刻返回,從而執(zhí)行ActivityThread中的消息循環(huán)噩峦,從而處理service創(chuàng)建等消息锭沟。詳見: http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/app/ActivityThread.java#1360

用官方文檔來(lái)說(shuō),就是service是運(yùn)行在主線程上的识补,也因此族淮,可能會(huì)引發(fā)ANR,所以耗時(shí)的工作應(yīng)該在service創(chuàng)建工作者線程來(lái)完成凭涂。

https://developer.android.com/guide/components/services.html?hl=zh-cn
注意:服務(wù)在其托管進(jìn)程的主線程中運(yùn)行祝辣,它既不創(chuàng)建自己的線程,也不在單獨(dú)的進(jìn)程中運(yùn)行(除非另行指定)切油。 這意味著蝙斜,如果服務(wù)將執(zhí)行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或聯(lián)網(wǎng)),則應(yīng)在服務(wù)內(nèi)創(chuàng)建新線程來(lái)完成這項(xiàng)工作澎胡。通過(guò)使用單獨(dú)的線程孕荠,可以降低發(fā)生“應(yīng)用無(wú)響應(yīng)”(ANR) 錯(cuò)誤的風(fēng)險(xiǎn),而應(yīng)用的主線程仍可繼續(xù)專注于運(yùn)行用戶與 Activity 之間的交互攻谁。

這樣做稚伍,其實(shí)有很多優(yōu)勢(shì),畢竟戚宦,主線程并非會(huì)一直運(yùn)行个曙,例如Activity后臺(tái)化等情況,如果service在獨(dú)立的線程中執(zhí)行受楼,顯然會(huì)消耗一定的資源垦搬。

不過(guò)這里說(shuō)的是service和調(diào)用方是同一進(jìn)程的情況祠挫,如果不同的進(jìn)程,理論是不是可以實(shí)現(xiàn)為同步呢悼沿?顯然不是的等舔,如果bindService阻塞主線程,導(dǎo)致5秒內(nèi)沒(méi)響應(yīng)輸入事件糟趾,這個(gè)時(shí)候會(huì)引發(fā)ANR慌植,而service執(zhí)行超時(shí)是20秒,因此為了規(guī)避這種問(wèn)題义郑,bindService采用異步設(shè)計(jì)蝶柿。

工作者線程阻塞方式bindService


很多時(shí)候,異步方式使用起來(lái)不是那么方便非驮,如果是在工作者線程交汤,可以使用同步方式來(lái)bindService,下面的代碼來(lái)自于: http://androidxref.com/5.0.0_r2/xref/frameworks/base/keystore/java/android/security/KeyChain.java

    public static KeyChainConnection bindAsUser(Context context, UserHandle user)
            throws InterruptedException {
        if (context == null) {
            throw new NullPointerException("context == null");
        }
        // 如果是非工作者線程劫笙,則拋出異常
        ensureNotOnMainThread(context);
        // 聲明一個(gè)阻塞隊(duì)列芙扎,bindService之后,等待這個(gè)隊(duì)列有數(shù)據(jù)入隊(duì)
        final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
        ServiceConnection keyChainServiceConnection = new ServiceConnection() {
            volatile boolean mConnectedAtLeastOnce = false;
            @Override public void onServiceConnected(ComponentName name, IBinder service) {
                if (!mConnectedAtLeastOnce) {
                    mConnectedAtLeastOnce = true;
                    try {
                        q.put(IKeyChainService.Stub.asInterface(service));
                    } catch (InterruptedException e) {
                        // will never happen, since the queue starts with one available slot
                    }
                }
            }
            @Override public void onServiceDisconnected(ComponentName name) {}
        };
        Intent intent = new Intent(IKeyChainService.class.getName());
        ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
        intent.setComponent(comp);
        boolean isBound = context.bindServiceAsUser(intent,
                                                    keyChainServiceConnection,
                                                    Context.BIND_AUTO_CREATE,
                                                    user);
        if (!isBound) {
            throw new AssertionError("could not bind to KeyChainService");
        }
        return new KeyChainConnection(context, keyChainServiceConnection, q.take());
    }

    private static void ensureNotOnMainThread(Context context) {
        Looper looper = Looper.myLooper();
        if (looper != null && looper == context.getMainLooper()) {
            throw new IllegalStateException(
                    "calling this from your main thread can lead to deadlock");
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末填大,一起剝皮案震驚了整個(gè)濱河市戒洼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌允华,老刑警劉巖圈浇,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異靴寂,居然都是意外死亡磷蜀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門百炬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)褐隆,“玉大人,你說(shuō)我怎么就攤上這事收壕〖斯啵” “怎么了轨蛤?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蜜宪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我祥山,道長(zhǎng)圃验,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任缝呕,我火速辦了婚禮澳窑,結(jié)果婚禮上斧散,老公的妹妹穿的比我還像新娘。我一直安慰自己摊聋,他們只是感情好鸡捐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著麻裁,像睡著了一般箍镜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上煎源,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天色迂,我揣著相機(jī)與錄音,去河邊找鬼手销。 笑死歇僧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锋拖。 我是一名探鬼主播诈悍,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兽埃!你這毒婦竟也來(lái)了写隶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤讲仰,失蹤者是張志新(化名)和其女友劉穎慕趴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鄙陡,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冕房,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趁矾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耙册。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖毫捣,靈堂內(nèi)的尸體忽然破棺而出详拙,到底是詐尸還是另有隱情,我是刑警寧澤蔓同,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布饶辙,位于F島的核電站,受9級(jí)特大地震影響斑粱,放射性物質(zhì)發(fā)生泄漏弃揽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矿微。 院中可真熱鬧痕慢,春花似錦、人聲如沸涌矢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娜庇。三九已至拇泛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間思灌,已是汗流浹背俺叭。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泰偿,地道東北人熄守。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像耗跛,于是被迫代替她去往敵國(guó)和親裕照。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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

  • Service是Android四大組件中與Activity最相似的組件调塌,他們都代表可執(zhí)行的程序晋南,Service與A...
    AndYMJ閱讀 1,804評(píng)論 0 3
  • 1.什么是Activity?問(wèn)的不太多负间,說(shuō)點(diǎn)有深度的 四大組件之一,一般的,一個(gè)用戶交互界面對(duì)應(yīng)一個(gè)activit...
    JoonyLee閱讀 5,731評(píng)論 2 51
  • 面試題總結(jié) 通用 安卓學(xué)習(xí)途徑, 尋找資料學(xué)習(xí)的博客網(wǎng)站 AndroidStudio使用, 插件使用 安卓和蘋果的...
    JingBeibei閱讀 1,674評(píng)論 2 21
  • 1.下列哪些語(yǔ)句關(guān)于內(nèi)存回收的說(shuō)明是正確的? (b )A、 程序員必須創(chuàng)建一個(gè)線程來(lái)釋放內(nèi)存 B姜凄、內(nèi)存回收程序負(fù)責(zé)...
    醉馬當(dāng)前闖閱讀 8,940評(píng)論 12 80
  • 小學(xué)四年級(jí)她和他初見政溃。 她并不知道他會(huì)是她守護(hù)8年的人。 她是霂堇态秧,剛剛經(jīng)歷了調(diào)班董虱,被自家班主任帶到了這...
    霡霂laaa閱讀 292評(píng)論 0 0