Android中的Service

什么是Service

Service是一個可以在后臺長時間執(zhí)行的應用組件。

Service的啟動方式

startService

  • 啟動方式
    在其他組件中調(diào)用startService()方法;
  • 停止方式
    在Service中調(diào)用stopSelf()方法;0
    在其他組件中調(diào)用stopService()方法;
  • Service與其他組件之間的通信方式
    沒有提供默認的通信。

bindService

  • 啟動方式
    在其他組件中調(diào)用bindService()方法;
  • 停止方式
    所有與Service綁定的組件都被銷毀;
    與Service綁定的組件調(diào)用unbindService()方法;
  • Service與其他組件之間的通信方式
    可以通過ServiceConnection進行通信,發(fā)送請求、獲取結(jié)果;
    可以通過IPC跨進程完成通信。
注意:
  • startService()和bindService()并不沖突,同一個Service可以即被組件調(diào)用startService()啟動,又被另一個組件調(diào)用bindService()綁定啟動。
    當同一個Service與其他組件同時存在這兩種調(diào)用聯(lián)系的時候,必須從兩種方法的角度看該Service均停止,該Service才能真正停止。
  • Service并不是運行在一個獨立的進程當中,而是依賴于創(chuàng)建Service時所在的應用程序進程。
    當某個應用程序進程被殺掉后,所有依賴于該進程的Service也會停止運行。

Service的創(chuàng)建

  • public void onCreate()
    只有在Service創(chuàng)建的時候調(diào)用一次。
  • public int onStartCommand(Intent intent,int flags,int startId)
    當組件調(diào)用startService()方法時,此方法被執(zhí)行,在這里進行Service的主要操作。
  • public IBinder onBind(Intent intent)
    當組件調(diào)用bindService()方法的時候調(diào)用,此時該Service將與組件綁定。
  • public void onDestroy()
    Service停止的時候調(diào)用該方法。

啟動Service

startService()

當組件調(diào)用startService()方法的時候,就可以啟動指定的Service了,同時這將導致Service中的onStartCommande()方法被調(diào)用。

Intent intent = new Intent(getContext(),Service.class);
startService(intent);

在調(diào)用startService()方法時候,傳入的Intent參數(shù)可以攜帶數(shù)據(jù),該數(shù)據(jù)將在Service執(zhí)行onStartCommand()方法中接收:

public int onStartCommand(Intent intent,int flags,int startId){}

bindService()

當組件調(diào)用bindService()方法的時候,將啟動指定的Service,并且將該組件與該Service進行綁定。
通常,將綁定它的組件稱為客戶端,將被綁定的Service稱為服務器。
要完成客戶端與服務器端的綁定,需要完成以下兩件事情:

  • 在客戶端完成bindService()的調(diào)用以及相關(guān)配置;
  • 在服務器端完成onBind()方法的重寫,返回一個IBinder接口給客戶端。

客戶端的配置

public boolean bindService(Intent service,ServiceConnection connection,int flags) {}

在bindService()方法中,需要三個參數(shù):

  • Intent:用來指定啟動哪一個Service,同時可以傳遞一些數(shù)據(jù);
  • ServiceConnection:用以實現(xiàn)客戶端與服務器端的關(guān)鍵類,此時我們需要重寫該類的兩個回調(diào)方法
    1.onServiceConneced()
    2.onServiceDisconnected()
    而我們可以通過這兩個回調(diào)方法得到服務端的IBinder對象,從而通過該IBinder對象實現(xiàn)客戶端與服務端的通信。
Service mService;
Service.Binder mBinder;
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name,IBinder service) {
        mBinder = (Service.Binder) service;
        mService = mBinder.gerService();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {}
}
  • int:用于指定綁定選項的標志,一般是BIND_AUTO_CREATE。

服務端的配置

如果要創(chuàng)建一個支持綁定的Service,我們必須要重寫它的onBind()方法。
這個方法返回一個IBinder對象,它是服務端對客戶端暴露的交互接口。
而要得到IBinder接口,通常有三種方式:

  • 繼承Binder類
  • 使用Messenger類
  • 使用AIDL
繼承Binder類

Binder類實現(xiàn)了IBinder接口,通過實現(xiàn)Binder類,客戶端可以直接通過這個類調(diào)用服務端的公有方法。
具體實現(xiàn)步驟:

  • 在Service類中,創(chuàng)建一個繼承Binder類的內(nèi)部類;
  • 在onBind()方法中返回這個Binder內(nèi)部類的實例;
  • 在客戶端中通過綁定Service獲得Binder內(nèi)部類的實例,通過它提供的方法進行后續(xù)的通信操作。
    服務端示例代碼:
public class LocalService extends Service {
    private final IBinder mBinder = new LocalBinder();
    private final Random mGenerator = new Random();
    public class LocalBinder extends Binder {
        public LocalService gerService() {
              return LocalService.this;
        }
    }

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

    public int getRandomNumber() {
        return mGenerator.netInt(100);
    }
}

LocalBinder為客戶端提供了getService()方法,用以獲得LocalService的當前實例。這樣,客戶端綁定服務端后,就可以調(diào)用服務中的公有方法(例如getRandomNumber())。
客戶端示例代碼:

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this,LocalService.class);
        bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mBond) {
            unbindService(mConnection);
        }
    }

    public void onButtonClick(View v) {
        if  (mBound) {
            int num = mService.getRandomNumber();
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(CompondName name,IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBound = false;
        }
    }
}
使用Messenger

Messenger的核心就是Message以及Handler來進行線程間的通信。
具體實現(xiàn)步驟:

  • 服務端實現(xiàn)一個Handler,由其接受來自客戶端的每一個調(diào)用的回調(diào);
  • 使用實現(xiàn)的Handler創(chuàng)建一個Messenger對象;
  • 通過Messenger得到一個IBinder對象,并將其通過onBind()返回給客戶端;
  • 客戶端使用IBinder將Messenger(引用服務的Handler)實例化,然后使用后者將Messag對象發(fā)送給服務;
  • 服務端在Handler中接收每個Message。
    使用該方法,客戶端通過傳遞Message來與服務端進行交互。
    服務端示例代碼:
public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;
    class ServiceHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case MSG_SAY_HELLO:
                    Toast.maktText(getApplicationContext(),"Hello",Toast.LENGTH_SHORT).show();
                    break;
            }
        }

        final Messenger mMessenger = new Messenger(new ServiceHandler());

        @Override
        public IBinder onBind(Intent intent) {
              return mMessenger.getBinder();//返回給客戶端一個IBinder實例,用于給客戶端構(gòu)造Messenger
        }
    }
}

服務端主要是返回給客戶端一個IBinder實例,以供客戶端構(gòu)造Messenger,并且處理客戶端發(fā)送過來的Message。
此時,我們需要在Manifests.xml中完成對Messenger的注冊。

<service
        android:name=".MessengerService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <anction android:name="com.mglee.messenger"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
</service>

客戶端示例代碼:

public class ActivityMessenger extends Activity {
    static final int MSG_SAY_HELLO = 1;
    Messenger mService = null;
    boolean mBound;
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name,IBinder service) {
            mService = new Messenger(service);//利用服務端返回的IBinder實例,構(gòu)造Messenger
            mBound = true;
        }

        public void onServiceDisconneted(ComponentName name) {
            mService = null;
            mBound = false;
        }

        public void sayHello() {
            if (mBound) {
                Message msg = new Message();
                msg.what = MSG_SAY_HELLO;
                try {
                    mService.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

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

    @Override
    protected void onStart() {
            super.onStart();

            Intent intent = new Intent("com.mglee.messenger");
            intent.setPackage("com.mglee");//包名是一定要設(shè)置的,不然會報錯
            bindService(intent,mConnection,BIND_AUTO_CREATE);
        }

    @Override
    protected void onStop() {
            super.onStop();

            if (mBound) {
                unbindService(mConnection);
                mBound = false;
            }
        }
    }
}

客戶端通過綁定服務獲取服務端返回的IBinder實例,借此構(gòu)造Messenger,從而用Messenger發(fā)送Message的方式與服務端進行交互。
上面的示例中,只是演示了客戶端向服務端的單方面數(shù)據(jù)通信,而要讓服務端向客戶端實現(xiàn)數(shù)據(jù)通信,只需要客戶端也創(chuàng)建一個Handler實例,讓它接受來自服務端的信息,同時讓服務端在客戶端給他發(fā)送的請求完成之后再給客戶端發(fā)送一條信息即可。

AIDL

AIDL,Android接口自定義語言。
既然是接口自定義語言,其實就是系統(tǒng)根據(jù)它完成IInterface實例的代碼,其實就是一種代碼模板。
使用AIDL實現(xiàn)服務端和客戶端通信的基本步驟:

  • 服務端創(chuàng)建一個AIDL文件,將需要暴露給客戶端的接口在里面聲明;
  • 在Service中實現(xiàn)這些接口;
  • 客戶端綁定服務端,并將onServiceConnected()得到的IBinder轉(zhuǎn)換為AIDL生成的IInterface實例;
  • 同構(gòu)得到的實例調(diào)用暴露的方法,完成與服務端的數(shù)據(jù)通信。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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