1. 程式人生 > >android activity和service的互動介紹

android activity和service的互動介紹

android開發中,作為4大元件的service在開發中經常會使用到。很多時候,我們的activity和service之間需要進行相應的互動,activity需要呼叫service裡面的方法實現某些功能,service需要呼叫activity的方法,實現介面更新等的互動。

實現2者之間相互互動的主要方式是:service中有個類部類繼承Binder,然後提供一個公有方法,返回當前service的例項。 activity通過bindService來開啟一個service,service通過onBind方法,返回一個IBinder例項(我們建立的那個類部類例項),activity中通過onServiceConnected方法,獲取IBinder例項,然後再通過IBinder例項來獲取service例項,這樣,我們得到了service的例項,那麼我們的activity就可以隨心所欲的使用它裡面的各種方法來操作它了。

上面activity可以操作service了,我們還需要service能操作activity。

我覺得可以有3中方式:

1.直接把activity傳給service,service通過activity例項隨便操作activity

2.使用介面回撥方式,activity實現相應的介面,service通過介面進行回撥,比較靈活

3.使用廣播

使用廣播是比較常見的方式,我們就不具體講解了,下面我們介紹前面2中方法,具體看程式碼,用service更新seekbar。

我們的activity程式碼:

package com.hck.bindservice;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;

import com.hck.bindservice.MyService.MyBuild;

public class MainActivity extends Activity {
   private MyService myService;  //我們自己的service
   private SeekBar pBar;  //模擬service更新進度條
   private ConnectionService connectionService;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		pBar = (SeekBar) findViewById(R.id.seekbar);
		connectionService=new ConnectionService();   
	}

	public void startService(View view) { //繫結service
       bindService(new Intent(this,MyService.class), connectionService, 1);
	}
	/**
	 * 
	 * @author Administrator
	 *實現service介面,用於service繫結時候,回撥
	 */
	class ConnectionService  implements ServiceConnection
	{
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			myService=((MyBuild)service).getMyService(); //獲取Myservice物件
			
			/**
			 * 直接把當前物件傳給service,這樣service就可以隨心所欲的呼叫本activity的各種可用方法
			 */
			myService.setMainActivity(MainActivity.this); //把當前物件傳遞給myservice
			
			
			/**
			 * 使用一個介面來實現回撥,這樣比上面方法更加靈活,推薦
			 */
//			myService.setOnProgressBarListener(new UpdateProgressListener() {
//				
//				@Override
//				public void updateBar(int size) {
//					updateBar(size);
//				}
//			});
			
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
	}
	/**
	 * 
	 * @param size
	 * 更新seekbar
	 */
	public void updateBar(int size)
	{
		pBar.setProgress(size);
	}
	
	/**
	 * 
	 * @param view
	 * 開始更新seekbar
	 */
	public void startBar(View view) {
	      if (myService==null) {
			Toast.makeText(this, "請先開始service", Toast.LENGTH_LONG).show();
		 }
	      else {
			myService.startUpdateProgress();
		}
		}
/**
 * 
 * @param view
 * 停止更新seekbar
 */
		public void stopBar(View view) {
			
			 if (myService==null) {
					Toast.makeText(this, "更新沒有開始", Toast.LENGTH_LONG).show();
				 }
			      else {
					myService.stopUpdateProgress();
				}
		}
/**
 * 
 * @param view
 * 停止service
 */
		public void stopService(View view) {
			myService=null;
				unbindService(connectionService);
			
			
			
			
		}
		@Override
			protected void onDestroy() {
				super.onDestroy();
				try {
					unbindService(connectionService);
				} catch (Exception e) {
				}
				
			}


}

重要程式碼是onServiceConnected回撥方法裡面

myService=((MyBuild)service).getMyService(); //獲取Myservice物件

獲取service物件後,我們想怎麼操作它都行了,比如上面的,把activity例項直接通過它的方法傳遞過去,便於

service呼叫activity的各種方法。或者,設定傳遞一個回撥介面物件過去,使用者回撥


service程式碼:

package com.hck.bindservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service{
   private int size=0;  
   private UpdateProgress updateProgress;
   private final long TIME=2000;
   private boolean isUpdate=true;
   private MainActivity activity;
   private UpdateProgressListener listener;
	@Override
	public IBinder onBind(Intent intent) {
		
		return new MyBuild();
	}
	@Override
	public void onCreate() {
		super.onCreate();
		updateProgress=new UpdateProgress();
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return super.onStartCommand(intent, flags, startId);
	}
	/**
	 * 
	 * @author Administrator
	 * 執行緒用來改變seekbar進度的大小
	 *
	 */
	class UpdateProgress implements Runnable
	{
		@Override
		public void run() {
			if (isUpdate) {
				  size+=10;
		           if (size>100) {
					size=0;
				}
		           handler.sendEmptyMessage(0);
			}
		}
	}
	/**
	 * 呼叫更新相應方法,更新進度條
	 */
	Handler handler=new Handler()
	{
		public void handleMessage(android.os.Message msg) {
			/**
			 * 直接呼叫activity物件裡面的方法
			 */
			if (activity!=null) {
				activity.updateBar(size);
			}
			
			/**
			 * 使用介面回撥
			 */
//			if (listener!=null) {
//				listener.updateBar(size);
//			}
			handler.postDelayed(updateProgress, TIME);
		};
	};
	
	/**
	 * 停止更新
	 */
	public void stopUpdateProgress()
	{
		isUpdate=false;
	}
	/**
	 * 開啟更新
	 */
	public void startUpdateProgress()
	{
		
		if (!isUpdate) {
			handler.post(updateProgress);
		}
		isUpdate=true;
	}
	public void onDestroy() {
		isUpdate=false;
	};
	
	/**
	 * 
	 * @param activity
	 * 初始化MainActivity物件
	 */
	public void setMainActivity(MainActivity activity)
	{
		this.activity=activity;
	}
	/**
	 * 
	 * @param listener
	 * 初始化UpdateProgressListener物件
	 */
	public void setOnProgressBarListener(UpdateProgressListener listener)
	{
		this.listener=listener;
	}
	
	/**
	 * 
	 * @author Administrator
	 * 使用類部類,返回當前service的例項,用於activity,呼叫service的各種方法
	 *
	 */
	class MyBuild extends Binder
	{
		public MyService getMyService()
		{
			return MyService.this;
		}
	}
	

}

service裡面最重要的就是,最下面我們的MyBuild類部類了,通過它的getMyService方法,獲取service的例項

該類的例項實在onBind時候,我們返回給activity的。

介面:

package com.hck.bindservice;

public interface UpdateProgressListener {
 public void updateBar(int size);
}


一個簡單介面,用於service回撥activity

上面是使用 bindService來啟動service的,那麼如果我們使用startService啟動service時候,上面的辦法就不行了。

因為onBind不會執行,我們獲取不到IBinder例項。這個時候,我們可以使用設計模式的觀察者模式來處理。

其它不清楚,還有什麼比較好的辦法沒有,我是沒有想到,有知道的朋友,請告知,謝謝

請把 private boolean isUpdate=true;    改為 private boolean isUpdate=false;