綁定方式的Service使用
在實現綁定服務時,最重要的是定義onBind()回調方法返回的介面,有三種方式:
1. 繼承Binder類
2. 使用Messenger
3. 使用AIDL
這裡對1,2方式進行分析。
1.繼承Binder類
如果你的服務是你的應用程式的私人服務,並且跟用戶端運行在同一個進程中,那麼就應該通過繼承Binder類來建立你的介面,並且佛從onBind()方法中返回這個介面的一個執行個體。用戶端接收這個Binder對象,並且能夠使用這個對象直接存取Binder類中實現的或Service中的公用方法。
使用官方SDK文檔中的例子:
ServiceShow.java
package com.luoye.servicelearn;import java.util.Random;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;public class ServiceShow extends Service{private final IBinder binder = new LocalBinder();//建立Service的內部IBinder對象public class LocalBinder extends Binder{ServiceShow getService() //實現Binder自己的方法,這裡返回Service對象的引用{return ServiceShow.this;}}public int getRandomNumber(){return (new Random()).nextInt(100);}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stub//返回一個IBinder對象,即Service的內部IBinder對象,作為ServiceConnection中onServiceConnected方法的IBinder傳入return binder; }}
MainActivity.java
package com.luoye.servicelearn;import com.luoye.servicelearn.ServiceShow.LocalBinder;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.view.Menu;import android.view.View;import android.widget.Toast;public class MainActivity extends Activity {ServiceShow localService;boolean bound = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void buttonOnClickListener(View v){switch(v.getId()){case R.id.start_service1:Intent intent_start = new Intent(this, ServiceShow.class);//綁定Service 第二個參數為ServiceConnection對象,由於bindService是非同步,//bindService()方法立即返回並且不返回IBinder對象,所以需要在ServiceConnection的方法中去處理//BIND_AUTO_CREATE表示if Service不存在,即onCreate()bindService(intent_start, connection, Context.BIND_AUTO_CREATE); break;case R.id.stop_service1:if(bound){unbindService(connection);bound = false;}//解除綁定Servicebreak;case R.id.show_random:if(bound == true){Toast.makeText(this, "number is :"+localService.getRandomNumber(), Toast.LENGTH_SHORT).show();}break;}}private ServiceConnection connection = new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubLocalBinder binder = (LocalBinder)service; //得到service的IBinder對象localService = binder.getService();//得到Service的引用,後續即可使用Service的方法bound = true;}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubbound = false;}};}
2. 使用Messenger
如果需要服務跟遠程進程通訊,那麼就可以使用Messenger對象來給服務提供介面。
以下是信使(Messenger)對象的使用概要:
1. 服務端實現的一個處理器(Handler介面),這個處理器針對每次來自用戶端的調用接收一次回調;
2. 這個處理器被用於建立一個信使對象(Messager)(這個信使對象要引用這個處理器);
3. 信使對象建立一個建立一個服務端從onBind()方法中返回給用戶端的IBinder對象;
4. 用戶端使用這個IBinder對象來執行個體化這個信使對象(信使引用了服務端的處理器),用戶端使用這個信使給服務端發送Message對象;
5. 服務端在它的處理器(Handler)的handleMessage()方法中依次接收每個Message對象
在這種方法中,沒有給用戶端提供服務端的方法調用,相反,用戶端會給發送服務端訊息(Message)對象,服務端會在它的處理器中接受這些訊息對象。
代碼:
ServiceShow.java
package com.luoye.servicelearn;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.widget.Toast;public class ServiceShow extends Service{static final int MSG_CODE = 0x10;//message的訊息類型定義class IncomingHandler extends Handler //message處理器,應與信使綁定{public void handleMessage(Message msg){switch(msg.what){case MSG_CODE:Toast.makeText(ServiceShow.this, "Hello world", Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);}}}//建立一個信使,該信使使用Handler對象作為msg的處理器final Messenger messenger = new Messenger(new IncomingHandler());@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubToast.makeText(ServiceShow.this, "Binding", Toast.LENGTH_SHORT).show();return messenger.getBinder();//返回對應信使的Binder,返回給client使用}}
MainActivity.java
package com.luoye.servicelearn;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.view.Menu;import android.view.View;public class MainActivity extends Activity {Messenger messenger;boolean bound = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void buttonOnClickListener(View v){switch(v.getId()){case R.id.start_service1:Intent intent_start = new Intent(this, ServiceShow.class);//綁定Service 第二個參數為ServiceConnection對象,由於bindService是非同步,//bindService()方法立即返回並且不返回IBinder對象,所以需要在ServiceConnection的方法中去處理//BIND_AUTO_CREATE表示if Service不存在,即onCreate()bindService(intent_start, connection, Context.BIND_AUTO_CREATE); if(bound){//產生message對象Message msg = Message.obtain(null, ServiceShow.MSG_CODE, 0, 0);try{//使用client端的信使發送message,該訊息會通過Binder對應的信使遞交到Service端的//信使,並由該端信使的訊息處理器Handler進行處理messenger.send(msg);}catch (Exception e){e.printStackTrace();}}break;case R.id.stop_service1:if(bound){unbindService(connection);//解除綁定Servicebound = false;}break;}}private ServiceConnection connection = new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubmessenger = new Messenger(service); //利用Service返回的信使的對應的IBinder來建立client端的信使對象bound = true;}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubmessenger = null;bound = false;}};}