Bound Service 詳解

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,但我只介紹兩種
  • 繼承Binder class
如果你的service是私有的並且和客戶端運行在同一個進程裏的話,你應該繼承Binder類並且從onBind()返回一個他的實例,客戶端接收這個Binder並且可以直接使用它在Binder實現裏或者是Service調用公共方法
  • 使用Message
如果你的接口需要在不同的進程裏處理工作,你可以用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">
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章