Android——Service 服務(wù)

描述

Service通程溃總是稱之為“后臺(tái)服務(wù)”么夫,其中“后臺(tái)”一詞是相對(duì)于前臺(tái)而言的盐茎,具體是指其本身的運(yùn)行并不依賴于用戶可視的UI界面兴垦;

因此,從實(shí)際業(yè)務(wù)需求上來(lái)理解字柠,Service的適用場(chǎng)景應(yīng)該具備以下條件:
1探越、并不依賴于用戶可視的UI界面(當(dāng)然,這一條其實(shí)也不是絕對(duì)的窑业,如前臺(tái)Service就是與Notification界面結(jié)合使用的)钦幔;
2、具有較長(zhǎng)時(shí)間的運(yùn)行特性常柄。

Service特性

1鲤氢、Service本身都是運(yùn)行在其所在進(jìn)程的主線程(如果Service與Clinet同屬于一個(gè)進(jìn)程,則是運(yùn)行于UI線程)西潘,但Service一般都是需要進(jìn)行”長(zhǎng)期“操作铜异,所以經(jīng)常寫(xiě)法是在自定義Service中處理”長(zhǎng)期“操作時(shí)需要新建線程,以免阻塞UI線程或?qū)е翧NR秸架;

2揍庄、Service一旦創(chuàng)建,需要停止時(shí)都需要顯示調(diào)用相應(yīng)的方法(startService需要調(diào)用stopService()或Service本身調(diào)用stopSelf(..);
bindService需要調(diào)用unbindService()东抹,否則對(duì)于startService將處于一直運(yùn)行狀態(tài)蚂子,對(duì)于bindService沃测,當(dāng)Client生命周期結(jié)束時(shí)也將因此問(wèn)題。也就是說(shuō)食茎,Service執(zhí)行完畢后蒂破,必須人為的去停止它。

startService

startService()啟動(dòng)Service后别渔,此時(shí)Service的生命周期與Client本身的什么周期是沒(méi)有任何關(guān)系的;
使用步驟如下:
1附迷、創(chuàng)建Service子類,繼承自Service

2哎媚、在AndroidManifest文件中注冊(cè)Service:
項(xiàng)目中的每一個(gè)Service都必須在AndroidManifest.xml中注冊(cè)才能生效喇伯。

3、啟動(dòng)Service:
當(dāng)?shù)谝淮螁?dòng)Service的時(shí)候拨与,會(huì)調(diào)用該Service中的onCreate()和onStartCommand(Intent intent, int flags, int startId)方法稻据。若再次啟動(dòng)Service,onCreate()不會(huì)被調(diào)用买喧,只有onStartCommand(Intent intent, int flags, int startId)方法才會(huì)調(diào)用捻悯。其中參數(shù)flags默認(rèn)情況下是0,對(duì)應(yīng)的常量名為START_STICKY_COMPATIBILITY淤毛。startId是一個(gè)唯一的整型今缚,用于表示此次Client執(zhí)行startService(...)的請(qǐng)求請(qǐng)求標(biāo)識(shí),在多次startService(...)的情況下低淡,呈現(xiàn)0,1,2....遞增姓言。

4、銷毀Service:
無(wú)論多少次的startService查牌,只需要一次stopService()即可將此Service終止事期,執(zhí)行onDestroy()函數(shù)(其實(shí)很好理解滥壕,因?yàn)閛nDestroy()與onCreate()回調(diào)是相對(duì)的)纸颜。

5、注意點(diǎn):
5.1绎橘、當(dāng)用戶強(qiáng)制kill掉進(jìn)程時(shí)胁孙,onDestroy()是不會(huì)執(zhí)行的。
5.2称鳞、對(duì)于同一個(gè)Service涮较,Service實(shí)例一次永遠(yuǎn)只存在一個(gè),而不管Client是否是相同的組件冈止,也不管Client是否處于相同的進(jìn)程中狂票。
5.3、Service通過(guò)startService(..)啟動(dòng)Service后熙暴,此時(shí)Service的生命周期與Client本身的什么周期是沒(méi)有任何關(guān)系的闺属,只有Client調(diào)用stopService(..)或Service本身調(diào)用stopSelf(..)才能停止此Service慌盯。當(dāng)然,當(dāng)用戶強(qiáng)制kill掉Service進(jìn)程或系統(tǒng)因內(nèi)存不足也可能kill掉此Service掂器。
5.4亚皂、Client A 通過(guò)startService()啟動(dòng)Service后,可以在其他Client(如Client B国瓮、Client C)通過(guò)調(diào)用stopService()結(jié)束此Service灭必。
5.5、Client調(diào)用stopService()時(shí)乃摹,如果當(dāng)前Service沒(méi)有啟動(dòng)禁漓,也不會(huì)出現(xiàn)任何報(bào)錯(cuò)或問(wèn)題,也就是說(shuō)峡懈,stopService()無(wú)需做當(dāng)前Service是否有效的判斷璃饱。
5.6、當(dāng)Service需要運(yùn)行在單獨(dú)的進(jìn)程中肪康,AndroidManifest.xml聲明時(shí)需要通過(guò)android:process指明此進(jìn)程名稱荚恶,當(dāng)此Service需要對(duì)其他App開(kāi)放時(shí),android:exported屬性值需要設(shè)置為true(當(dāng)然磷支,在有intent-filter時(shí)默認(rèn)值就是true)谒撼。

自定義Service
public class MyService extends Service {

    public static final String TAG = "MyService";

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

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

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

    //返回具體的IBind對(duì)象
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

在AndroidManifest文件中注冊(cè)Service
<service
      android:name=".MyService"
      android:exported="false">
</service>
startService
public class ServiceTestOneActivity extends BaseActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        Log.e("ServiceTestOneActivity",
                "ServiceTestOneActivity thread id is " + Thread.currentThread().getId());

        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                startService(startIntent);
            }
        });

        findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                stopService(stopIntent);
            }
        });
    }

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

}

bindService

bindService的主要特性在于Service的生命周期是依附于Client的生命周期的,當(dāng)Client銷毀時(shí)雾狈,bindService將執(zhí)行onDestroy廓潜。

同時(shí)通過(guò)Service中的Binder對(duì)象可以較為方便進(jìn)行Client-Service通信。bindService一般使用過(guò)程如下:
1善榛、創(chuàng)建Service子類辩蛋,繼承自Service,并重寫(xiě)onBind(Intent intent)方法移盆,此方法中需要返回具體的Binder對(duì)象悼院。

2、Client通過(guò)實(shí)現(xiàn)ServiceConnection接口來(lái)自定義ServiceConnection咒循,并通過(guò)bindService (Intent service, ServiceConnection sc, int flags)方法將Service綁定到此Client上据途;

3、自定義的 ServiceConnection 中實(shí)現(xiàn) onServiceConnected(ComponentName name, IBinder binder)方法叙甸,獲取Service端Binder實(shí)例颖医;

4、通過(guò)獲取的Binder實(shí)例進(jìn)行Service端其他公共方法的調(diào)用裆蒸,以完成Client-Service通信熔萧;

5、當(dāng)Client在恰當(dāng)?shù)纳芷冢ㄈ鏾nDestroy等)時(shí),此時(shí)需要解綁之前已經(jīng)綁定的Service佛致,通過(guò)調(diào)用函數(shù)unbindService(ServiceConnection sc)遂赠。

6、注意點(diǎn)
6.1晌杰、bindService()會(huì)調(diào)用Service的與onCreate()和 onBind()方法跷睦,不會(huì)調(diào)用onStartCommand()方法,但是會(huì)調(diào)用ServiceConnection中的onServiceConnected()方法肋演。
6.2抑诸、unbindService()銷毀服務(wù)會(huì)調(diào)用Service的onUnBind()方法。
6.3爹殊、如果關(guān)閉當(dāng)前Activity蜕乡,必須在Activity的 onDestroy()中取消綁定Service。
6.4梗夸、不可重復(fù)調(diào)用unbindService()取消綁定层玲,否則會(huì)出現(xiàn) Service not registered 異常。
6.5反症、當(dāng)Activity關(guān)閉后辛块,如果沒(méi)有調(diào)用unbindService()取消綁定服務(wù),此Service會(huì)自動(dòng)調(diào)用 onDestroy()方法铅碍,但是這種方式是不安全的润绵,建議主動(dòng)取消綁定。

自定義BinderService
public class MyService extends Service {

    public static final String TAG = "MyService";
    public boolean isServiceBind = false;

    public MyBinder myBind = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "MyService thread id is " + Thread.currentThread().getId());
        Log.e(TAG, "onCreate() executed");
        createForegroundService();
    }

    //創(chuàng)建前臺(tái)服務(wù)
    private void createForegroundService() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
        Notification.Builder builder = new Notification.Builder(getApplicationContext());
        builder.setContentTitle("***服務(wù)");
        builder.setContentText("請(qǐng)勿關(guān)閉胞谈,***");
        builder.setSmallIcon(R.mipmap.service_icon);
        builder.setContentIntent(pendingIntent);
        Notification notification = builder.build();

        //啟動(dòng)前臺(tái)服務(wù)
        startForeground(1,notification);
    }

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

    // 返回具體的IBind對(duì)象
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind() executed");
        isServiceBind = true;
        return myBind;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        isServiceBind = false;
        Log.e(TAG, "onUnbind() executed");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //停止前臺(tái)服務(wù)
        stopForeground(true);
        Log.e(TAG, "onDestroy() executed");
    }

    public void doSomeThing() {
        Log.e(TAG, "doSomeThing() executed");
    }

    public class MyBinder extends Binder {

        public MyService getService() {
            return MyService.this;
        }

        public void doWork() {
            Log.e("MyBind", "doWork() executed");
        }
    }
}

使用bindService啟動(dòng)
public class ServiceTestOneActivity extends BaseActivity {

    private MyService myService;
    private MyService.MyBinder myBinder;

    private MyReceiver myReceiver;
    private ServiceConnection connection = new ServiceConnection() {

        public static final String TAG = "ServiceConnection";

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 服務(wù)斷開(kāi)連接
            Log.e(TAG, "onServiceDisconnected() executed");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 服務(wù)連接成功尘盼,可得到IBinder對(duì)象,也可以通過(guò)IBinder得到Service實(shí)例
            Log.e(TAG, "onServiceConnected() executed");
            myBinder = (MyService.MyBinder) service;
            myService = myBinder.getService();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        Log.e("ServiceTestOneActivity",
                "ServiceTestOneActivity thread id is " + Thread.currentThread().getId());

        initBroadcast();

        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                startService(startIntent);
            }
        });

        findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                stopService(stopIntent);
            }
        });

        findViewById(R.id.bt_bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關(guān)聯(lián)后自動(dòng)創(chuàng)建Service,
                // 這會(huì)使得MyService中的onCreate()方法得到執(zhí)行烦绳,但onStartCommand()方法不會(huì)執(zhí)行卿捎。
                Intent bindIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
            }
        });

        findViewById(R.id.bt_unbind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkServiceIsBind();
            }
        });

        findViewById(R.id.bt_do_work).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != myService && null != myBinder) {
                    myService.doSomeThing();
                    myBinder.doWork();
                }
            }
        });
    }

    private void checkServiceIsBind() {
        if (null != myService && myService.isServiceBind) {
            myService = null;
            myBinder = null;
            unbindService(connection);
        }
    }

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

startService和bindService交叉使用

如果既點(diǎn)擊了Start Service按鈕,又點(diǎn)擊了Bind Service按鈕會(huì)怎么樣呢径密?

這個(gè)時(shí)候你會(huì)發(fā)現(xiàn)午阵,不管你是單獨(dú)點(diǎn)擊Stop Service按鈕還是Unbind Service按鈕,Service都不會(huì)被銷毀睹晒,必需將兩個(gè)按鈕都點(diǎn)擊一下趟庄,Service才會(huì)被銷毀括细。也就是說(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ì)被銷毀锉试。

Service和Thread

實(shí)際上Service和Thread是沒(méi)有任何關(guān)系的,Service實(shí)際上就運(yùn)行在主線程上览濒。

1呆盖、Android的后臺(tái)就是指拖云,它的運(yùn)行是完全不依賴UI的。即使Activity被銷毀应又,或者程序被關(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)題了旬蟋。

2油昂、Activity很難對(duì)Thread進(jìn)行控制,當(dāng)Activity被銷毀之后倾贰,就沒(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被銷毀了我衬,之后只要重新與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)行控制的情況破加。

3、一個(gè)比較標(biāo)準(zhǔn)的Service就可以寫(xiě)成:

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 開(kāi)始執(zhí)行后臺(tái)任務(wù)
                }
            }).start();
            return super.onStartCommand(intent, flags, startId);
        }

        //或者
        class MyBinder extends Binder {
            public void startDownload() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 執(zhí)行具體的下載任務(wù)
                    }
                }).start();
            }
        }

創(chuàng)建前臺(tái)Service

前臺(tái)服務(wù)是那些被認(rèn)為用戶知道(用戶所認(rèn)可的)且在系統(tǒng)內(nèi)存不足的時(shí)候不允許系統(tǒng)殺死的服務(wù)雹嗦。前臺(tái)服務(wù)必須給狀態(tài)欄提供一個(gè)通知范舀,它被放到正在運(yùn)行(Ongoing)標(biāo)題之下——這就意味著通知只有在這個(gè)服務(wù)被終止或從前臺(tái)主動(dòng)移除通知后才能被解除。

Service幾乎都是在后臺(tái)運(yùn)行的了罪,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ì)的信息蛾茉,非常類似于通知的效果。

ex:App中的音樂(lè)播放服務(wù)應(yīng)被設(shè)置在前臺(tái)運(yùn)行(前臺(tái)服務(wù))——在App后臺(tái)運(yùn)行時(shí)撩鹿,便于用戶明確知道它的當(dāng)前操作谦炬、在狀態(tài)欄中指明當(dāng)前歌曲信息、提供對(duì)應(yīng)操作节沦。

            //創(chuàng)建前臺(tái)服務(wù)
            private void createForegroundService() {
                Intent notificationIntent = new Intent(this, MainActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
                Notification.Builder builder = new Notification.Builder(getApplicationContext());
                builder.setContentTitle("***服務(wù)");
                builder.setContentText("請(qǐng)勿關(guān)閉吧寺,***");
                builder.setSmallIcon(R.mipmap.service_icon);
                builder.setContentIntent(pendingIntent);
                Notification notification = builder.build();

                //啟動(dòng)前臺(tái)服務(wù)
                startForeground(1,notification);
            }

            @Override
            public void onDestroy() {
                super.onDestroy();
                //停止前臺(tái)服務(wù)
                stopForeground(true);
            }

IntentService

1、IntentService是繼承于Service并處理異步請(qǐng)求的一個(gè)類散劫。
注意這句話——“繼承于Service”和“處理異步請(qǐng)求”稚机。
“繼承于Service”表示他是一個(gè)服務(wù),我們知道Service是存在于主線程的获搏,它之中不能存在耗時(shí)操作赖条,否則的話回應(yīng)起ANR,因此便有了IntentService——這個(gè)封裝了HandlerThread和Handler的特殊Service常熙。

2纬乍、特性:
2.1、IntentService中只有“一個(gè)”默認(rèn)的HandlerThread線程用來(lái)處理異步任務(wù);
2.2裸卫、默認(rèn)直接實(shí)現(xiàn)了onBind()方法仿贬,直接返回null,并定義了抽象方法onHandlerIntent()墓贿,用戶自定義子類時(shí)茧泪,需要實(shí)現(xiàn)此方法;
2.3聋袋、onHandlerIntent()主要就是用來(lái)處于相應(yīng)的“長(zhǎng)期”任務(wù)的队伟,并且已經(jīng)自動(dòng)在新的線程中,用戶無(wú)語(yǔ)自定義新線程幽勒;
2.4嗜侮、當(dāng)“長(zhǎng)期”任務(wù)執(zhí)行完畢后(也就是onHandlerIntent()執(zhí)行完畢后),此IntentService將自動(dòng)結(jié)束啥容,無(wú)需人為調(diào)用方法使其結(jié)束锈颗;
2.5、IntentService處理任務(wù)時(shí)咪惠,也是按照隊(duì)列的方式一個(gè)個(gè)去處理击吱,而非真正意義上的多線程并發(fā)方式。
2.6硝逢、onHandleIntent(Intent)發(fā)生在子線程姨拥,不能直接更新UI,需要先把結(jié)果發(fā)到Activity中
2.7渠鸽、提交的任務(wù)順序執(zhí)行叫乌,如果一個(gè)任務(wù)A正在IntentService中執(zhí)行,此時(shí)發(fā)送另一個(gè)異步任務(wù)B到IntentService中徽缚,那么必須等到任務(wù)A執(zhí)行完之后任務(wù)B才會(huì)開(kāi)始執(zhí)行

3憨奸、使用IntentService的好處:
3.1、我們省去了在 Service 中手動(dòng)開(kāi)線程的麻煩凿试,
3.2排宰、當(dāng)操作完成時(shí),我們不用手動(dòng)停止 Service那婉。

自定義IntentService
public class MyIntentService extends IntentService {

    public static final String TAG = "MyIntentService";

    public static final String ACTION_ONE = "action_one";
    public static final String ACTION_TWO = "action_two";
    public static final String ACTION_BROADCAST = "action_broad";
    private int progressOne, progressTwo;

    //無(wú)參的構(gòu)造方法板甘,指定線程名稱
    public MyIntentService() {
        // 線程的名稱
        super("MyIntentService");
    }

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

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

    //實(shí)現(xiàn)此方法,處理異步任務(wù)详炬,此方法運(yùn)行在子線程(即HandlerThread)
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null && intent.getAction() != null) {
            switch (intent.getAction()) {
                case ACTION_ONE:
                    while (progressOne < 100) {
                        progressOne++;
                        //發(fā)送廣播通知UI線程更新UI
                        sendBroadcast(getUpdateIntent(0, progressOne));
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case ACTION_TWO:
                    while (progressTwo < 100) {
                        progressTwo++;
                        //發(fā)送廣播通知UI線程更新UI
                        sendBroadcast(getUpdateIntent(1, progressTwo));
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
        }
    }

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

    private Intent getUpdateIntent(int i, int progress) {
        Intent intent = new Intent(ACTION_BROADCAST);
        intent.putExtra("type", i);
        intent.putExtra("progress", progress);
        return intent;
    }

}

啟動(dòng)IntentService
public class ServiceTestOneActivity extends BaseActivity {

    private TextView textViewOne;
    private TextView textViewTwo;

    private MyReceiver myReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        textViewOne = findViewById(R.id.tv_one);
        textViewTwo = findViewById(R.id.tv_two);

        initBroadcast();

        findViewById(R.id.bt_intent_one).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
                intent.setAction(MyIntentService.ACTION_ONE);
                startService(intent);
            }
        });

        findViewById(R.id.bt_intent_two).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
                intent.setAction(MyIntentService.ACTION_TWO);
                startService(intent);
            }
        });
    }

    // 注冊(cè)廣播
    private void initBroadcast() {
        myReceiver = new MyReceiver();
        registerReceiver(myReceiver, new IntentFilter(MyIntentService.ACTION_BROADCAST));
    }

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

    public class MyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case MyIntentService.ACTION_BROADCAST:
                    if (intent.getIntExtra("type", 0) == 0) {
                        textViewOne.setText(intent.getIntExtra("progress", 0) + "");
                    } else {
                        textViewTwo.setText(intent.getIntExtra("progress", 0) + "");
                    }
                    break;
            }
        }
    }

}

遠(yuǎn)程服務(wù)盐类,即AIDL實(shí)現(xiàn)進(jìn)程間通信

Android Interface Definition Language,也就是Android接口定義語(yǔ)言呛谜。是的在跳,首先我們知道的第一點(diǎn)就是:AIDL是一種語(yǔ)言。
實(shí)現(xiàn)步驟:
1隐岛、創(chuàng)建AIDL文件猫妙,會(huì)自動(dòng)生成aidl文件。創(chuàng)建成功后再/main目錄下自動(dòng)創(chuàng)建aidl文件夾聚凹。


圖片.png
// IMyAIDLService.aidl
package com.android.pkqup.androidnote.service_test;

// Declare any non-default types here with import statements

interface IMyAIDLService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int plus(int a, int b);

    String toUpperCase(String str);
}

2割坠、創(chuàng)建Service,以IMyAIDLService.Stub()實(shí)例作為IBinder對(duì)象在onBind()方法中返回妒牙。

public class RemoteService extends Service {
    
    public static final String TAG = "RemoteService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate() executed");
        Log.e(TAG, "ServiceTestOneActivity process id is " + Process.myPid());
    }

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

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

    // 返回具體的IBind對(duì)象
    @Override
    public IBinder onBind(Intent intent) {
       //以AIDL的Stub作為IBinder返回
        return binder;
    }

    IMyAIDLService.Stub binder = new IMyAIDLService.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString) throws RemoteException {
        }

        // 相加
        @Override
        public int plus(int a, int b) throws RemoteException {
            return a + b;
        }

        // 轉(zhuǎn)大寫(xiě)
        @Override
        public String toUpperCase(String str) throws RemoteException {
            if (str != null) {
                return str.toUpperCase();
            }
            return null;
        }
    };
}

3韭脊、在AndroidManifest文件中注冊(cè)遠(yuǎn)程Service。
注意:android:process=":remote"

       <service
            android:exported="true"
            android:name=".service_test.RemoteService"
            android:process=":remote">
            <!--給遠(yuǎn)程service創(chuàng)建一個(gè)意圖過(guò)濾器 提供給其他應(yīng)用做隱式意圖-->
            <intent-filter>
                <action android:name="com.android.pkqup.androidnote.remote.service" />
            </intent-filter>
       </service>

4单旁、復(fù)制整個(gè)aidl文件夾到第三方工程的 /main 目錄下沪羔。

5、在第三方應(yīng)用中bindService象浑。

private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IMyAIDLService myAIDLService = IMyAIDLService.Stub.asInterface(service);
            try {
                int result = myAIDLService.plus(50, 50);
                String upperStr = myAIDLService.toUpperCase("comes from ClientTest");
                Log.d("TAG", "result is " + result);
                Log.d("TAG", "upperStr is " + upperStr);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private void bindService() {
        Intent intent = new Intent("com.android.pkqup.androidnote.remote.service");
        //Android5.0之后服務(wù)必須顯性聲明蔫饰,所以在調(diào)用其他應(yīng)用的遠(yuǎn)程服務(wù)時(shí)必須加上包名,
        intent.setPackage("com.android.pkqup.androidnote");
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愉豺,一起剝皮案震驚了整個(gè)濱河市篓吁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚪拦,老刑警劉巖杖剪,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冻押,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盛嘿,警方通過(guò)查閱死者的電腦和手機(jī)洛巢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)次兆,“玉大人稿茉,你說(shuō)我怎么就攤上這事〗嫣浚” “怎么了漓库?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)园蝠。 經(jīng)常有香客問(wèn)我渺蒿,道長(zhǎng),這世上最難降的妖魔是什么彪薛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任蘸嘶,我火速辦了婚禮,結(jié)果婚禮上陪汽,老公的妹妹穿的比我還像新娘训唱。我一直安慰自己,他們只是感情好挚冤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布况增。 她就那樣靜靜地躺著,像睡著了一般训挡。 火紅的嫁衣襯著肌膚如雪澳骤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天澜薄,我揣著相機(jī)與錄音为肮,去河邊找鬼。 笑死肤京,一個(gè)胖子當(dāng)著我的面吹牛颊艳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忘分,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼棋枕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了妒峦?” 一聲冷哼從身側(cè)響起重斑,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肯骇,沒(méi)想到半個(gè)月后窥浪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祖很,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年漾脂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了假颇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡符相,死狀恐怖拆融,靈堂內(nèi)的尸體忽然破棺而出蠢琳,到底是詐尸還是另有隱情啊终,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布傲须,位于F島的核電站蓝牲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泰讽。R本人自食惡果不足惜例衍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望已卸。 院中可真熱鬧佛玄,春花似錦、人聲如沸累澡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)愧哟。三九已至奥吩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蕊梧,已是汗流浹背霞赫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肥矢,地道東北人端衰。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像甘改,于是被迫代替她去往敵國(guó)和親靴迫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345