Android學習筆記18——Bound Services

         一個Bound Service在客戶端和服務器接口中是一個服務器。Bound Service允許組件綁定到這個Service,發送請求,接受響應,甚至表現出進程間通信。Bound Service僅僅當它服務於另一個應用程序組件時纔會存活,並且不能獨立的運行在後臺。

        Bound Service是一個Service類的實現,允許其他應用程序綁定他並且和他進行交互。爲了綁定一個Service,你必須實現onBind回調方法,這個方法返回一個IBind對象,這個IBind對象定義了客戶端和服務器交互的程序接口。

        一個客戶端能夠調用bindService方法綁定到Service,當它連接的時候,它必須提供一個ServiceConnection的實現,它控制着與這個Service的連接。這個bindService方法不會返回任何值,但是當系統創建客戶端與服務器的連接時,它會調用ServiceConnecte類的onServiceConnected()方法,客戶端能夠用IBinder和這個Service通訊。

         在同一時間,可以有多個客戶端連接到這個Service,然而僅僅當第一個客戶端和這個Service綁定的時候系統纔會調用Service的onBind方法獲取IBind對象。系統將會發送同樣的IBind到其他要綁定這個Service的客戶端,而不是再次調用oBind方法。

        當最後一個客戶端和這個Service解除綁定的時候,系統就會銷燬這個Service。

        當我們實現我們的Bound Service的時候,最重要的部分是定義我們Service的onBind回調方法返回的接口。我們可以有一下三種方式來定義這個接口。

 第一、繼承Binder這個類

         如果我們的Service是對於我們的應用程序是私有的並且和客戶端運行在同一個進程中,我們應該繼承Binder這個類來創建我們的接口,並且從onBind方法中返回一個Binder的實例。當我們要爲我們的應用程序創建一個後臺的工作時,這種做法是一種比較好的做法。

第二、使用一個Messager

         如果我們希望我們的接口能夠跨進行進行工作,我們可以用Messager來爲我們的Service創建一個接口。用這種方法,我們定義一個Handler去響應不同類型的Messager對象。這個Hanlder是一個Messager對象和一個客戶端分享IBinder的基礎,運行客戶端用Messager對象發送命令給這個Service。另外,客戶端也可以定義自己的Messgaer對象,因此這個Service也能夠發送Messager給客戶端。

第三、使用AIDL

        AIDL(Android Interface Define Language)所做的工作是把對象分解成操作系統能夠識別的原生的語言,並且安排他們跨進程進行進程間的通訊。以上所說的Messager技術,就是基於AIDL。正如前面所提到過的,Messager對象創建了在線程中爲所有客戶端請求創建一個請求隊列,因此這個Service一次僅能接收一個請求。然而,如果我們想要我們的Service能夠一次接受多個請求,我們可以直接使用AIDL,在這種情況下,你的Service必須能夠勝任多線程並且實現安全的。

    我們爲了使用AIDL,我們需要定義一個.aidl文件,這個文件定義了程序的接口。Android SDK工具用這個文件生成了一個抽象類,這個抽象類定義了定義了接口和操作IPC的實現,在我們的Service中我們可以繼承這個抽象類。

注意:大多數情況下,我們一般來說不會使用AIDL來創建一個Bound Service,因爲它可能需要一個多線程的兼容並且導致一個更加複雜的實現。正因爲如此,AIDL不太適合大多數的應用程序,所以我們不會在這裏進行講解關於AIDL的用法。

繼承Binder類的講解

如果我們的Service僅僅需要在我們自己的應用程序中使用並且不需要跨進程工作,那麼我們可以通過繼承Binder來實現我們自己的Binder,這個Binder可以讓客戶端直接訪問我們的Service。

注意,這種方法僅僅適用於客戶端和服務端在同一個應用程序和進程中,例如,一個音樂播放應用程序需要把一個Activty和一個在後臺播放音樂的Service進行綁定的時候,這種方式將會是一個很好做法。

1、首先,在我們的Service中我們可以創建一個IBinder的實例通過一下幾種方式

      1>包含這個客戶端能夠訪問的公共方法;

      2>返回當前Service的實例,這個實例中的公共方法客戶端可以訪問;

      3>或者,返回被這個Service主導的另一個類的實例,這個實例包含了可以被客戶端訪問的公共方法;

2、從onBinder這個回調方法中返回Binder的實例;

3、在客戶端中接受到來自onServiceConnected()回調方法;

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

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

    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}
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();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute) */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call were something that might hang, then this request should
            // occur in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

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

使用Messager對象

如果我們想要和遠程的Service進行通訊,你能使用Messager對象來來爲你的Service提供接口。這種技術允許你不必通過AIDL來表現進程間通訊。

下面是一些如何使用Messager對象的總結:

1、Service實現一個Handler,這個Handler接收每一個來自客戶端請求的回調;

2、這個Handler被用來創造一個Messager對象;

3、而這個Meeager對象創建一個IBinder對象,這個Binder對象從這個Service的onBind()方法中返回到客戶端;

4、客戶端用這個IBinder實例化這個Messager,客戶端用這個IBinder給這個Service發送一個Messager對象;

5、這個Service在它的Handler對象的handleMessage()方法中接收沒一個請求。

<span style="font-size:12px;">public class MessengerService extends Service {
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}</span>
<span style="font-size:12px;">public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}</span>


發佈了43 篇原創文章 · 獲贊 25 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章