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。下面是这种生命周期:























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