Bound Service 詳解
一個bound service是一個存在於 client-server交互的service,,一般不會在後臺無限期的運行,一個bound Service允許組件如activity去bound,發送請求,接收回應,甚至進行進程間的交流。
基礎
爲了提供一個bound service,你必須實現onBind()回調方法,這個方法返回一個定義了編程接口的IBinder對象,利用這個對象客戶端可以和service進行service
一個client可以調用bindService()來綁定一個Service,如果這樣做了,你必須實現ServiceConnection用於和Service進行交流,bindService()方法沒有返回值,但當安卓系統創建了在客戶端和Service的連接,它可以調用在ServiceConnection裏的onServiceConnected()方法去發送可以供客戶端與Service進行交流的IBinder。
多種客戶端可以同時連接service,但是這個系統只調用你的Service類裏的onBind()方法去檢索第一個客戶端綁定的IBinder,並不會每一次都調用onBind()方法
當最後一個客戶端不再綁定service了,系統將會銷燬這個Service(除非這個Service也被startService()方法啓動)
創建一個Bound Service
有三中方法定義一個bound service,但我只介紹兩種
如果你的service是私有的並且和客戶端運行在同一個進程裏的話,你應該繼承Binder類並且從onBind()返回一個他的實例,客戶端接收這個Binder並且可以直接使用它在Binder實現裏或者是Service調用公共方法
如果你的接口需要在不同的進程裏處理工作,你可以用Message創建一個接口,用這種方法,這個Service定義一個Handler去響應不同類型的Message,然後可以和客戶端分享IBinder,允許客戶端使用Message發送命令到這個Service,這個客戶端可以定義一個自己的Messager,這樣的話Service也可以發送信息
這是最簡單的方法執行進程間的交流,因爲Messenger將所有的請求都排列進入一個單個的線程,因此你不必考慮你的Service的線程安全
繼承Binder class
步驟
1.在你的Service裏,創建一個Binder實例
包含客戶端可以調用的公共方法,
返回當前Service實例,或者返回被Service寄宿的其他類,同時也必須包含供客戶端調用的公共方法
2.從onBind()方法裏返回一個Binder實例
3.在客戶端裏,從onServiceConnectioned()方法裏接收這個Binder
實例
這是MainActivity類
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.View;
import android.widget.Toast;
import com.example.boundservice.FirstService.LocalBinder;
public class MainActivity extends Activity {
FirstService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
System.out.println("onStart1-------");
// Bind to LocalService
Intent intent = new Intent(this, FirstService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public void onButtonStop(View v)
{
System.out.println("onButtonStop------");
unbindService(mConnection);
}
@Override
protected void onStop() {
super.onStop();
System.out.println("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.
System.out.println("onButton-----------");
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) {
System.out.println("onServiceConnected-------");
// 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) {
System.out.println("onServiceDisconnected--------");
mBound = false;
}
};
}
這是MainActivity類的xml配置文件
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start"
android:onClick="onButtonClick"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="89dp"
android:layout_marginTop="55dp"
android:onClick="onButtonStop"
android:text="stop" />
這是FirstService類
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class FirstService extends Service{
private final IBinder mBinder = (IBinder) new LocalBinder();
private final Random mGenerator = new Random();
public class LocalBinder extends Binder
{
FirstService getService()
{
System.out.println("LocalBinder------");
return FirstService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("onBind------");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("onUnbind-------");
return super.onUnbind(intent);
}
public int getRandomNumber()
{
return mGenerator.nextInt(100);
}
}
使用Messager
如果你需要你的Service進行遠程將的交流,那麼你可以使用Messager提供一個接口,這個方法允許不使用AIDL你去執行進程間的交流
這裏是一些關於使用Messager的總結
- 這個service實現一個可以接受來自客戶端的每一個回調方法r的Handler
- 這個Handler被使用去創建一個Messager對象
- 這個Messager創建一個IBinder,這個Service通過onBind()返回給客戶端
- 客戶端使用這個IBinder去實例化一個Messager,客戶端使用Messager發送message對象給service
- 通過這種方式,客戶端沒有在service調用方法,取而代之的是,客戶端發送Messages,Service在handler裏接收
這是一個使用Messager的簡單例子
這是MainActivity類
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.os.RemoteException;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Messenger mService = null;
boolean mBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// 當這個連接在客戶端和service被建立起來的時候,這個方法會被調用
// 提供給我們可以和Service交互的object,我們與Service使用Messenger進行交流,
System.out.println("onServiceConnected---------被調用");
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// 當 連接斷開的時候,這個方法被調用
System.out.println("onServiceDisconnected--------被調用");
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
System.out.println("你按下了按鈕");
if (!mBound) return;
// 創建並且發送一個message給Service
Message msg = Message.obtain(null, MessagerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onStart() {
System.out.println("onStart--------被調用");
super.onStart();
// 綁定一個Service
bindService(new Intent(this, MessagerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
System.out.println("onStop---------被調用");
super.onStop();
//撤銷與一個Service的綁定
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
這MainActivity類的xml配置文件
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="29dp"
android:layout_marginTop="20dp"
android:text="send"
android:onClick="sayHello" />
這是MessagerService類
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 MessagerService extends Service{
// 控制Service展示一個message
static final int MSG_SAY_HELLO = 1;
// 處理來自客戶端的Message
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
System.out.println("handleMessage-------被調用");
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
// 我們給客戶端提供的一個“靶子”,這個靶子發送Message給IncomingHandler
final Messenger mMessenger = new Messenger(new IncomingHandler());
// 當綁定到一個服務時,給我們的Messager返回一個接口
@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind----------被調用");
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
記得加在<application>元素里加
<service android:name="MessagerService"></service>
這是在Logcat裏的結果
這樣我們就可以看清楚這些方法的執行過程,希望對你們有所幫助
</pre></div><div><pre name="code" class="java">