1. 程式人生 > >Android 四大元件之Service的啟動、繫結小述

Android 四大元件之Service的啟動、繫結小述

一、概述

學習過Android的小夥伴就不可能不知道Service是什麼,因為Service是Android四大元件之一,聲名赫赫有木有,所以在這裡我就不詳細介紹了,本節主要還是充當筆記的作用,因為我待記性如初戀,記性虐我千百遍。

二、Service的建立

Service是一種無介面互動的android元件,並不同於一般服務的概念,它並不意味著Service將建立執行緒或者程序,事實上預設情況下,Service總是執行在主執行緒之中,所以它本身並不能做耗時操作,否則就會導致ANR。建立Service的方式很簡單,只要繼承Service類即可,我們來看下程式碼

    public
class MyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.i("Tag", "onCreate"); } }

在Manifest清單檔案中註冊該Service

        <service android:name=".MyService">
            <intent-filter>
                <action android:name="com.servicetest.MyService" />
            </intent-filter>
        </service>

三、Service的工作狀態

Service分為兩種工作狀態,一種是啟動狀態,我們通過startService的方式啟動,主要用於執行後臺計算,例如下載任務、播放音樂、檔案I/O等場景;另一種是繫結狀態,通過bindService

的方式繫結,主要用於其他元件與Service的互動,Service提供公共的功能,供自己或其它應用來呼叫,例如系統的感測器服務、定位服務等場景。需要注意的是,這兩種狀態是可以共存的,即Service既可以處於啟動狀態,又可以同時處於繫結狀態。下面我們就來具體的看下兩種狀態和之間的差別:

(1)startService啟動服務

如果一個元件通過startService啟動一個Service,那麼Service就會獨立執行,不再與該元件產生任何關係。啟動的程式碼也很簡單

        Intent startServiceIntent = new Intent("com.servicetest.MyService");
        startService(startServiceIntent);

當然我們也可以通過stopService來手動結束該Service

        stopService(startServiceIntent);

好了,啟動方法是不是非常簡單,接下來我們就簡單分析下startService()啟動服務時,Service的生命週期方法,正常情況下,系統會先呼叫服務的onCreate()方法,接著呼叫onStartCommand()方法。

        onCreate()>>onStartCommand()

當然,當我們通過stopService結束服務時,系統會先呼叫服務的onDestroy()方法

        onDestroy()

需要注意的是,當我們多次呼叫startService啟動同一個服務時,該服務的onCreate()方法並不會多次呼叫,但是onStartCommand()方法會被呼叫多次

(2)bindService繫結服務

通過bindService繫結(啟動)一個服務後,Service會為該元件提供一個介面,我們可以通過該介面實現元件與Service的互動。程式碼也很簡單

    public class MainActivity extends AppCompatActivity {

        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                // iBinder即服務連線後返回的介面,我們通過該介面來呼叫Service提供的功能
            }
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
            }
        };

        private void startService() {
            // 開啟服務
            Intent startServiceIntent = new Intent("com.servicetest.MyService");
            bindService(startServiceIntent, conn, BIND_AUTO_CREATE);
        }

        private void stopService() {
            // 解除繫結,結束服務
            unbindService(conn);
        }
}

好了,繫結服務也不是難點,同樣的,我們也來分析下,當我們bindService繫結一個服務時,Service的生命週期方法,正常情況下,系統會先呼叫服務的onCreate()方法,接著呼叫onBind()方法。

        onCreate()>>onBind()

這個時候元件和Service就繫結在了一起,一旦呼叫者退出了,那麼系統就會先呼叫Service的onUnbind()方法,隨後呼叫Service的onDestroy()方法。當然我們也可以直接通過unbindService()方法解除與當前服務的連線,呼叫該方法也會導致系統呼叫Service的onUnbind()方法,隨後呼叫Service的onDestroy()方法。

        onUnbind()>>onDestroy()

需要注意的是,如果呼叫bindService前服務已經被繫結,那麼多次呼叫bindService並不會導致多次建立與繫結服務,也就是說,Service的onCreate()方法和onBind()方法不會重複呼叫

四、Service的通訊

當我們建立一個Service後,呼叫者該怎麼與Service進行通訊呢?例如傳值或者呼叫Service提供的方法,下面我們就來簡單看下幾種情況:

(1)startService的Intent傳值

當我們在Activity中開啟一個Service時,我們可以通過Intent進行通訊,程式碼如下,在這裡我們是通過startService方式開啟的

        private void startService() {
            Intent startServiceIntent = new Intent("com.servicetest.MyService");
            startServiceIntent.putExtra("intent_tag", 0);
            startService(startServiceIntent);
        }

當然相應的,在我們的Service中,我們要通過onStartCommand()方法獲取資料

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // 能夠接收呼叫者傳遞過來的資料
            if(intent != null){
                int tag = intent.getIntExtra("intent_tag", -1);
                Log.i("Tag", "onStartCommand"+tag);
            }
            return super.onStartCommand(intent, flags, startId);
        }

(2)bindService的Intent傳值

當我們通過bindService方式繫結一個服務時,我們也可以通過Intent進行資料傳遞,操作方法與startService方式類似

        private void startService() {
            Intent startServiceIntent = new Intent("com.servicetest.MyService");
            startServiceIntent.putExtra("intent_tag", 0);
            bindService(startServiceIntent, conn, BIND_AUTO_CREATE);
        }

與startService方式不同的是,我們需要在已繫結的服務的onBind方法中獲取資料

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            // 能夠接收呼叫者傳遞過來的資料
            if(intent != null){
                int tag = intent.getIntExtra("intent_tag", -1);
                Log.i("Tag", "onBind"+tag);
            }
            return null;
        }

(3)bindService的IBinder方法呼叫

當我們通過bindService方式繫結一個服務後,我們還能進行更為靈活的互動,例如直接呼叫Service內的方法

    public class MyService extends Service {

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            // 能夠接收呼叫者傳遞過來的資料
            if(intent != null){
                int tag = intent.getIntExtra("intent_tag", -1);
                Log.i("Tag", "onBind"+tag);
            }
            return new MyIbinder();
        }

        @Override
        public void onCreate() {
            super.onCreate();
            Log.i("Tag", "onCreate");
        }

        class MyIbinder extends Binder {
            // 我們通過內部類MyIbinder的方法,呼叫Service的方法或屬性
            public String getName() {
                return getServiceDescription();
            }
        }

        private String getServiceDescription() {
            return this.getPackageName() + "MyService";
        }

        @Override
        public boolean onUnbind(Intent intent) {
            Log.i("Tag", "onUnbind");
            return super.onUnbind(intent);
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("Tag", "onDestroy");
        }
    }

我們在Activity中通過ServiceConnection匿名類來呼叫Service中的方法,實現與Service的互動

        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                MyService.MyIbinder binder = (MyService.MyIbinder)iBinder;
                String description = binder.getName();
                Log.i("Tag","description:" + description);
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
            }
        };

五、總結

本節主要簡單介紹了Service的建立、啟動、繫結和與Activity互動的方法,如果想要檢視更多Service的基礎知識,去我的部落格目錄裡檢視吧,因為關於每塊知識點的介紹,部落格單節寫的比較零散,不容易查詢。