2025-05-23

如果你的service僅被自己的應用使用並且不需跨進程工作,那麼你可以實現你自己的Binder類使得你的客戶端能直接使用service的公開接口方法.

註:這隻在客戶端和service位於同一應用和同一進程中時才能工作,其實大多數都是這種情況.例如,在一個音樂應用需要把它的activity綁定到它自己的播放音樂的後臺service時,這種方式就會很好地工作.

 

下面是如何建立它:

在你的service中,創建一個Binder實例,提供以下三種功能之一:

Binder包含一些可供客戶端調用的公開方法.

返回當前的Service實例,它具有一些客戶端可以調用的公開方法.

或者,返回另一個類的實例,這個類具有客戶端可調用的公開方法並托管於service.

在回調方法onBind()中返回這個Binder的實例.

在客戶端,從回調方法onServiceConnected()中接收這個Binder並使用1中所述的公開方法調用綁定service.

註:service和客戶端必須位於同一應用的理由是這樣可以使客戶端正確地轉換返回的對象並調用它的公開方法.service和客戶端必需要位於同一個進程中,因為這樣就不必執行跨進程的封送處理瞭.

 

例如,這下面這個service提供讓客戶端通過一個Binder實現調用service中的方法的功能:

[java] public class LocalService extends Service { 
    // Binder given to clients  
    private final IBinder mBinder = new LocalBinder(); 
    // Random number generator  
    private final Random mGenerator = new Random(); 
 
    /**
     * 用於客戶端Binder的類.因為我們我們知道這個
     * service永遠運行在與客戶端相同的進程中,所以我們不需要處理IPC.
     */ 
    public class LocalBinder extends Binder { 
        LocalService getService() { 
            // 返回本service的實例到客戶端,於是客戶端可以調用本service的公開方法  
            return LocalService.this; 
        } 
    } 
 
    @Override 
    public IBinder onBind(Intent intent) { 
        return mBinder; 
    } 
 
    /**客戶端所要調用的方法*/ 
    public int getRandomNumber() { 
      return mGenerator.nextInt(100); 
    } 
}<span style="color:#000000;"> 
</span> 
public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * 用於客戶端Binder的類.因為我們我們知道這個
     * service永遠運行在與客戶端相同的進程中,所以我們不需要處理IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // 返回本service的實例到客戶端,於是客戶端可以調用本service的公開方法
            return LocalService.this;
        }
    }

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

    /**客戶端所要調用的方法*/
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}<span style="color:#000000;">
</span>

 

類LocalBinder提供提供瞭getService()方法使得客戶端能取得當前LocalService的實例.於是客戶端就可以調用service中的公開方法瞭.比如,客戶端可以調用service的getRandomNumber()方法.

下面是一個綁定到LocalService並且在按鈕按下時調用getRandomNumber()的actvity的例子:[java] public class BindingActivity extends Activity { 
    LocalService mService; 
    boolean mBound = false; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
    } 
 
    @Override 
    protected void onStart() { 
        super.onStart(); 
        // 綁定到類LocalService的實例www.aiwalls.com  
        Intent intent = new Intent(this, LocalService.class); 
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 
    } 
 
    @Override 
    protected void onStop() { 
        super.onStop(); 
        // 從service解除綁定  
        if (mBound) { 
            unbindService(mConnection); 
            mBound = false; 
        } 
    } 
 
    /** 當按鈕按下時調用(在layout文件中定義的button並用android:onClick 屬性指定響應到本方法) */ 
    public void onButtonClick(View v) { 
        if (mBound) { 
            // 調用LocalService的一個方法  
            // 然而,如果這個調用中有掛起操作,那麼這個請求應發  
            // 生在另一個線程來避免拉低activity的性能.  
            int num = mService.getRandomNumber(); 
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); 
        } 
    } 
 
    /** 定義service綁定的回調,傳給bindService() 的*/ 
    private ServiceConnection mConnection = new ServiceConnection() { 
 
        @Override 
        public void onServiceConnected(ComponentName className, 
                IBinder service) { 
            //我們已經綁定到瞭LocalService,把IBinder進行強制類型轉換並且獲取LocalService實例.  
            LocalBinder binder = (LocalBinder) service; 
            mService = binder.getService(); 
            mBound = true; 
        } 
 
        @Override 
        public void onServiceDisconnected(ComponentName arg0) { 
            mBound = false; 
        } 
    }; 

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // 綁定到類LocalService的實例
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 從service解除綁定
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** 當按鈕按下時調用(在layout文件中定義的button並用android:onClick 屬性指定響應到本方法) */
    public void onButtonClick(View v) {
        if (mBound) {
            // 調用LocalService的一個方法
            // 然而,如果這個調用中有掛起操作,那麼這個請求應發
            // 生在另一個線程來避免拉低activity的性能.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** 定義service綁定的回調,傳給bindService() 的*/
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            //我們已經綁定到瞭LocalService,把IBinder進行強制類型轉換並且獲取LocalService實例.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

上面的例子展示瞭客戶端如何使用一個ServiceConnection的實例和onServiceConnected()方法綁定到service.
註:上面的例子沒有明確地從service解除綁定.但是所有的客戶端都應該在合適的時候解除綁定(比如當activity暫停時).

 

摘自  nkmnkm的專欄 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *