版權聲明:本文為部落客原創文章,轉載請标明出處。 https://blog.csdn.net/chaoyu168/article/details/51078622
Service按照其啟動的方式,可分為兩種:
1、Started
Started的Service,通過在Application裡用startService(Intent
intent)方法來啟動。這種類型的Service一經啟動,會在後面無休止地運作,即使啟動它的Activity被Destroy掉。要停止此類型的Service,可在Service中調用stopSelf()或在Application中調用stopService(Intent intent),要不然就隻能等Android系統在系統資源緊張的時候把它殺掉。
2、Bound
Bound的Service,通過在Application裡調用bindService()方法來啟動。該類型的Service與Application綁定在一起,一旦綁定的所有Application消失了,Android會Detroy掉該Service。也可以主動調用unbindService()方法來解綁Service。
有時候我們想在Activity中獲知Service的狀态,例如一個音樂播放器,Service負責音樂播放,Activity負責顯示目前歌曲名和播放進度。
可以用Broadcast,這個也不失為一個解決方法。
但如果可以擷取Service執行個體,那麼就可以調用Service中自定義的一些方法來擷取Service狀态了。
首先要明确的是,第一種類型的Service是無能為力的。因為Activity與Service之間并沒有相關聯的接口,即使這個Service是在Activity裡start的,一旦start,兩者不再有關聯。
一、本地Service調用。
如果Activity與Service在同一應用程式中,兩者間的互動就屬于本地Service調用。
可通過bindService實作,具體操作如下:
1、自定義子類MyService,繼承Service類
2、在MyService類中,自定義内部類MyBinder,繼承Binder類
在内部類中,根據需要互動的資料,建立一些方法,以便Activity可通過這些方法得到Service中的一些資料。或者幹脆通過一個方法傳回Service執行個體。
public class MyBinder extends Binder
{
public MyService getServiceInstance()
{
return MyService.this;
}
}
3、在Service類中,new一個MyBinder私有成員,并在onBind()方法中return一個MyBinder執行個體。
之是以這樣做,是因為Service一旦綁定,就會回調onBind()方法,并傳回一個Binder對象給Activity。具體看下一個步驟。
4、在Activity中覆寫ServiceConnection接口中的onServiceConnected(ComponentName name, IBinder service)方法,
其中的service參數就是MyService類中onBind()方法傳回的MyBinder對象,調用MyBinder對象的自定義方法getServiceInstance()可得到Service執行個體。
下面是一個DEMO:
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
MusicInterface mi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MusicService.class);
//混合調用
//為了把服務所在程序變成服務程序
startService(intent);
//為了拿到中間人對象
bindService(intent, new MusicServiceConn(), BIND_AUTO_CREATE);
}
class MusicServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mi = (MusicInterface) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
//開始播放按鈕
public void play(View v){
mi.play();
}
//暫停播放按鈕
public void pause(View v){
mi.pause();
}
}
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class MusicService extends Service{
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new MusicController();
}
//必須繼承binder,才能作為中間人對象傳回
class MusicController extends Binder implements MusicInterface{
public void play(){
MusicService.this.play();
}
public void pause(){
MusicService.this.pause();
}
}
public void play(){
System.out.println("播放音樂");
}
public void pause(){
System.out.println("暫停播放");
}
}
public interface MusicInterface {
void play();
void pause();
}
二、跨程序Service調用
跨程序Service調用,即在目前應用程式中,調用另一個應用程式中的Service。
因為Android中,每個應用程式都運作于自己的程序中,擁有獨立的Dalvik虛拟機執行個體,因而稱為跨程序調用(Inter-Process Comunication)。
可通過AIDL服務來實作。
AIDL(Android Interface Definition Language),是Android定義的一種類似Java的語言。主要用于定義跨程序調用時,服務端跟用戶端用于資料互動的接口。
AIDL服務并不支援所有的Java資料類型。它隻支援以下的幾種類型:
1、Java的簡單類型(int, char, boolean等)。無需import
2、String和CharSequence。無需import
3、List和Map。無需import(應當注意的是:List和Map的元素類型必須是AIDL支援的)
4、AIDL自動生成的接口。需要import
5、實作android.os.Parcelable接口的類。需要import
建立簡單的AIDL服務的步驟如下:
(一)服務端步驟:
1、在服務端建立AIDL檔案IMyAidl.aidl
AIDL與Java代碼很相近,示例代碼如下:(注意:aidl檔案字尾名為.aidl)
interface IMyAidl
{
void print();
}
建立完aidl檔案後,ADT會自動調用aidl指令生成相應的Java檔案。可檢視gen檔案夾下是否有一個名為IMyAidl.java的檔案。如果沒有,說明.aidl檔案有誤。
2、繼承Service類,在子類中,将AIDL接口暴露出來。
這一步類似于本地Service調用,則通過onBind(Intent
intent)方法傳回一個IBinder對象。
示例代碼如下:
public class MyService extends Service
{
private AidlBinder mBinder;
//Stub類是上一步驟中,aidl指令生成的Java代碼中的一個類
//該類實作了IBinder接口和IMyAidl接口
//可以通過繼承該類,然後在onBind()方法中傳回AidlBinder對象
//如此一來,即可通過AidlBinder對象對AIDL檔案中定義的方法進行調用
public class AidlBinder extends Stub
{
@Override
public void print()
{
System.out.println("Hello world!")//實作AIDL檔案中的接口函數
}
}
@Override
public void onCreate()
{
mBinder = new AidlBinder();//啟動服務時即建立Binder對象
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;//傳回Binder對象,讓用戶端獲得Binder對象
}
}
3、配置AndroidManifest.xml檔案
<!-- 自定義通路Service所需的權限 -->
<permission android:protectLevel="normal" android:name="thomas.permission.AIDL_SERVICE"/>
<service android:name="com.thomas.aidlserver.MyService" android:exported="true"
android:permission="thomas.permission.AIDL_SERVICE">
<!-- IntentFilter屬性是必不可少的 -->
<!-- 如此一來,用戶端才能通過該action遠端調用服務端的Service -->
<intent-filter>
<action android:name="com.thomas.aidlserver.action.AIDL_SERVICE"/>
</intent-filter>
</service>
(二)用戶端步驟:
1、建立AIDL檔案
用戶端也要建立AIDL檔案,而且是跟服務端完全一樣的AIDL檔案。
複制服務端AIDL檔案即可。應當注意的是:AIDL檔案的包名一定要跟服務端的一緻。
如果用戶端沒有該包,應建立一個包,并将AIDL檔案放到包下。
2、跨程序調用Service
用戶端跨程序調用Service的方法與本地調用Service的方法差不多,也是通過bindService()。
應當注意的是,調用成功後,通過ServiceConnection接口中的onServiceConnected(ComponentName
name, IBinder service)方法得到服務端onBind()方法傳遞過來的Binder對象。将該對象類型轉化為AIDL檔案中聲明的接口類型,即可調用該接口中定義的方法。
private IMyAidl mAidl;
mServiceCon = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
//将IBinder類型轉化為IMyAidl類型。
mAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisonnected(ComponentName name){}
}
//遠端Service綁定,其中Intent的action參數是服務端在
//AndroidManifest.xml檔案中<service>标簽下的<intent-filter>指定的字元串
bindService(new Intent("com.thomas.aidlserver.action.AIDL_SERVICE"),
mServiceCon, Service.BIND_AUTO_CREATE);
mAidl.print();//調用AIDL檔案中聲明的方法
<!-- 請求通路遠端Service所需的權限,該權限定義于服務端的AndroidManifest.xml檔案中 -->
<uses-permission android:name="thomas.permission.AIDL_SERVICE"/>