android bind service

轉載請註明出處:http://blog.csdn.net/zhouli_csdn/article/details/45498809


Bound Services

綁定服務允許組件綁定到服務,發送請求,接收結果,甚至進程間通信。綁定服務僅僅存活於服務於其它組件的時候,它不會長期在後臺運行。

The basics

爲了提供綁定服務,你必須實現onBind方法,這個方法返回一個IBinder,定義了交互的接口。你必須實現ServiceConnection類,監控服服務的連接。bindService方法並不會立刻返回一個值,但是當系統建立了client和service的連接時,它會調用ServiceConnection的onServiceConnected方法,並且傳遞IBinder。多個clients可以綁定到一個服務,但是隻有第一個client調用onBind方法時,纔會調用onBind方法,以後就不會調用了。當最後一個client調用unBind方法時,系統會殺死這個服務(除非也調用startService)。

Creating a Bound Service

你必須提供一個IBinder,三種方法:
繼承Binder類:
如果你的service對於你的應用是私有的,並且在同一個進程中運行,你可以實現該類,並通過onBind方法返回該類的一個實例。這時,client就可以訪問IBinder和Service中的public方法。如果你的服務被其它應用使用或者運行在單獨的進程中,你不能使用這種方法
Using a Messenger:
如果你需要一個接口工作於不同的進程,你可以爲service創建一個Messenger接口。這種方法,service定義了一個Handler處理不同類型的請求。Messenger能夠和client分享一個IBinder,允許client使用Message發送請求。通常,client也可以定義一個Messenger,這樣service可以將Message送回。
這是最簡單的進程間通信,因爲Messenger將所有的請求都入列到一個線程中,這意味着一次只能執行一個請求,所以你不必擔心線程安全問題。
Using AIDL:
AIDL做了所有的工作使得可以將對象分解成操作系統可以理解的原語,然後在不同進程間執行IPC。Messenger方法底層就是使用了AIDL 的機制實現的。如果你想service能夠同時處理多個請求,你可以直接使用AIDL。這種情況下,你必須實現多線程安全問題。
要使用AIDL,你必須創建一個.aidl文件來定義編程接口。你可以使用sdk工具來根據這個文件生成一個抽象類(繼承該接口)處理IPC。
接下來你可以在service中繼承該抽象類。
注意:大多數應用程序不該使用AIDL來創建一個bind service.因爲這會造成多線程安全問題,如果你想實現,你可以參照android的AIDL文檔。

繼承Binder類:

注意:這僅僅只有client和service在同一個應用並且在同一個進程中纔會有效。
1在service中創建一個IBinder對象:
1).包含一些public方法,這樣client可以調用
2).返回當前service對象(包含一些public方法,client可以調用),
3).或者返回一個service的內部類包含一些public方法,這樣client可以調用
2.在onBind方法中返回IBinder對象實例。
3.在client中,從onServiceConnected方法接收這個Binder。然後調用提供的方法調用服務。
注意:之所以client和service必須在同一個應用中是因爲這樣纔可以使client轉換返回的對象和調用它的apis。因爲這種方法並不會在進程間通信,所以必須在同一進程運行。

例如:
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);
    }
}
LocalBInder提供了getService方法給client,並返回當前service對象。這樣client就可以調用service的public方法。
下面的例子是activity調用service的public方法:
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;
        }
    };
}

使用Messenger:

如果你希望你的service可以使用遠程進程調用,你可以使用這種方法。它可以是你避免使用AIDL實現進程間通信。
如何使用:
1.service實現一個Handler接口,接收client的請求調用
2.這個Handler用來創建一個Messenger對象,並且包含了此handler的一個引用。
3.這個Messenger對象創建一個IBinder對象,並通過onBind方法返回給client。
4.client用這個IBinder對象實例化這個包含了service的handler的Messenger對象,client使用這個handler發送Message給service。
5.service在它的handleMessage方法中處理message。
這種方法,client不會調用service的方法,而是通過發送給service的message交給handler處理。
下面是一個例子:
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();
    }
}
client僅僅只需要根據service返回的IBinder對象在ServiceConnection的onServiceConnected方法中創建Messenger對象,並通過send方法發送消息。例子:
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;
        }
    }
}
如果你希望service應答,你需要自client中創建一個Messenger,當client接收到onServiceConnected方法時,通過send方法將messenger發送給service。

注意:僅僅activity,contentprovider,service可以綁定到一個服務,broadcastreceiver不能夠綁定到一個服務

ServiceConnection:

onServiceConnected:系統調用這個方法傳遞由onBind方法返回的IBinder
onServiceDisconnected:系統會在和服務的連接意外丟失時調用此方法。例如:當service崩潰或者被殺死。client調用unBind方法時並不會調用此方法。

當client被銷燬時,它會解除和service的綁定,但是你應該在和service完成交互時或者你的activity執行pause時解除綁定。這時,服務就可以在不用的時候結束。

bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
第三個參數應該爲BIND_AUTO_CREATE,這樣在service還沒有創建時可以創建service。

需要注意的地方:

1.你必須注意DeadObjectException,當連接破壞的時候會被調用。這是唯一的一個被遠程方法拋出的異常。
2.objects是被跨進程引用計數。
3.你應該在client的匹配的生命週期進行onBind和unBind。
1)例如你只希望在activity可見時與服務通信,那麼你可以在onStart中onBind,在onStop中unBind。
2)如果你想在activity停止時仍然可以收到結果,你可以在onCreate和onDestroy中執行。必須知道的是,這意味着你的activity在整個生命週期中都會使用service。如果service運行在兩外一個進程中,所以你增加了進程的殺死權重,系統很可能會殺死它。
注意:不要再activity的onResume和onPause方法中onBind和unBind。因爲如果有多個activities綁定到一個服務。並且其中兩個有一個過渡,那麼你在過渡過程中首先可能會銷燬服務,然後在下一個activity創建服務。

管理綁定服務的生命週期

如果你的服務接受綁定,當系統調用unBind方法時,如果你希望在下一次一個client綁定到service時被系統調用onRebind方法而不是onBind方法時,你可以在unBind方法中返回true。onRebind返回void,但是client仍然可以在onServiceConnected方法中接收到IBinder。下面是這種生命週期:























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章