Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android筆記----Service組件

Android筆記----Service組件

編輯:關於Android編程

Service簡介

跨進程調用Service(AIDL服務)

電話管理器

短信管理器

 

 

 

Service簡介

Service是Android四大組件中與Activity最相似的組件,它們都代表可執行的程序。Service與Activity的區別在於: Service一直在後台運行,它沒有用戶界面,一旦Service被啟動起來之後,它與Activity一樣,也具有自己的生命周期。

Service組件也是可執行程序,它也有自己的生命周期。創建、配置Service與創建配置Activity的過程基本相似,下面介紹Service的開發過程。

1.1 開發Service

開發Service的步驟如下:

定義一個繼承Service的子類。

在AndroidManifest.xml文件中配置該Service。

與Activity相似的是, Service中也定義了一系列生命周期的方法,如下所示:

onStartCommand():每當客戶端調用startService(Intent)方法啟動該Service時都會回調該方法。

IBinder onBind(Intent intent):該方法是Service子類必須實現的方法,通過返回的IBinder對象,與其他Service進行通信。

onCreate():當該Service第一次被創建時回調該方法。

onDestroy():當該Service被關閉之前將會回調該方法。

onUnbind():當Service上綁定的所有客戶端都斷開連接時將會回調該方法。

配置Service使用,也可為元素配置子元素,用於說明該service可被哪些Intent啟動。

Android系統中, Service不能夠自己運行,需要通過一個Activity或者其他Context對象來調用,啟動Service有兩種方法:

通過Context的startService()方法:通過該方法啟動Service,訪問者與Service之間沒有關聯,即使訪問者退出了, Service仍在運行。

通過Context的bindService()方法:通過該方法啟動Service,訪問者與Service綁在了一起,訪問者一旦退出, Service也就終止。

 

例:Service使用:

MainActivity.java

public class MainActivity extends Activity
{
	Button start , stop;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 獲取程序界面中的start、stop兩個按鈕
		start = (Button) findViewById(R.id.start);
		stop = (Button) findViewById(R.id.stop);
		//創建啟動Service的Intent
		final Intent intent = new Intent();
		//為Intent設置Action屬性
		intent.setAction(com.boby.service.FIRST_SERVICE);		
		start.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View arg0)
			{
				//啟動指定Serivce
				startService(intent);	
			}
		});
		stop.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View arg0)
			{
				//停止指定Serivce
				stopService(intent);	
			}
		});		
	}
}

 

在配置文件中配置Service:

 

 

1.2 綁定本地Service並與之通信

當程序通過startService()和stopService()啟動、關閉Service時,Service與訪問者之間基本上不存在太多關聯,因此Service和訪問者之間也無法進行通信、數據交換。

如果要Service和訪問者交換數據需要進行方法調用或者數據交換。則應該使用bindService()和unbindService()啟動和關閉服務。

通過Context的bindService(Intent service,ServiceConnection conn, int flags),當訪問者與Service之間連接成功時將回調該ServiceConnection對象的onSerciceConnected(ComponentName name,IBinder service)方法,當訪問者與Service之間斷開連接時將回調ServiceConnection的onSerciceDisconnected(ComponentName name)方法。

當開發Service類時,該Service類必須提供一個IBinder onBind(Intent intent)方法,在綁定本地Service的情況下,onBind(Intent intent)方法返回的IBinder對象將會傳遞給onSerciceConnected(ComponentName name,IBinder service)方法中的service參數,這樣訪問者就可以通過該IBinder對象與Service進行通信。

 

例:Activity綁定本地Service:

MainActivity.java

public class MainActivity extends Activity
{
	Button bind , unbind , getServiceStatus;
	// 保持所啟動的Service的IBinder對象
	BindService.MyBinder binder;
	// 定義一個ServiceConnection對象
	private ServiceConnection conn = new ServiceConnection()
	{
		// 當該Activity與Service連接成功時回調該方法
		@Override
		public void onServiceConnected(ComponentName name
			, IBinder service)
		{
			System.out.println(--Service Connected--);
			// 獲取Service的onBind方法所返回的MyBinder對象
			binder = (BindService.MyBinder) service;
		}
		// 當該Activity與Service斷開連接時回調該方法
		@Override
		public void onServiceDisconnected(ComponentName name)
		{
			System.out.println(--Service Disconnected--);			
		}
	};
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 獲取程序界面中的start、stop、getServiceStatus按鈕
		bind = (Button) findViewById(R.id.bind);
		unbind = (Button) findViewById(R.id.unbind);
		getServiceStatus = (Button) findViewById(R.id.getServiceStatus);
		//創建啟動Service的Intent
		final Intent intent = new Intent();
		//為Intent設置Action屬性
		intent.setAction(com.boby.service.BIND_SERVICE);		
		bind.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View source)
			{
				//綁定指定Serivce
				bindService(intent , conn , Service.BIND_AUTO_CREATE);	
			}
		});
		unbind.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View source)
			{
				//解除綁定Serivce
				unbindService(conn);
			}
		});	
		getServiceStatus.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View source)
			{
				// 獲取、並顯示Service的count值
				Toast.makeText(MainActivity.this
					, Serivce的count值為: + binder.getCount()
					, 4000)
					.show();
			}
		});
	}
}

 

在配置文件中配置Service:

 
 

 

1.3 Service的生命周期

應用程序中啟動Service的方式不同, Service的生命周期也略有差異。

 

跨進程調用Service(AIDL服務)

2.1 AIDL服務簡介

跨進程訪問(AIDL服務)Android系統中的進程之間不能共享內存,因此,需要提供一些機制在不同進程之間進行數據通信。

為了使其他的應用程序也可以訪問本應用程序提供的服務,Android使用一種接口定義語言(Interface Definition Language,IDL)來公開服務的接口。因此,可以將這種可以跨進程訪問的服務稱為AIDL(Android Interface Definition Language)服務。

Android的遠程Service調用,需要先定義一個遠程調用的接口,然後提供該接口的實現類。

客戶端訪問本地Service時, Service只是將一個回調對象(IBinder對象)通過onBind()方法返回給客戶端。遠程Service的onBind()方法只是將IBinder對象的代理傳給客戶端的ServiceConnection的onServiceConnected方法的第二個參數。當客戶端獲取了遠程Service的IBinder對象的代理後,就可以通過該IBinder對象去回調遠程Service的屬性或方法了。

 

2.2 建立AIDL服務的步驟
建立AIDL服務要比建立普通的服務復雜一些,具體步驟如下:
(1)在Eclipse Android工程的Java包目錄中建立一個擴展名為aidl的文件。該文件的語法類似於Java代碼,但會稍有不同。
(2)如果aidl文件的內容是正確的,ADT會自動生成一個Java接口文件(*.java)。
(3)建立一個服務類(Service的子類)。
(4)實現由aidl文件生成的Java接口。
(5)在AndroidManifest.xml文件中配置AIDL服務,尤其要注意的是,標簽中android:name的屬性值就是客戶端要引用該服務的ID,也就是Intent類的參數值。

 

2.3 將數據暴露給客戶端

上一步定義好一個AIDL接口之後,接下來定義一個Service的實現類,該Service的onBind()方法所返回的IBinder對象應該是ADT所生成的ICat.Stub的子類的實例。

 

AndroidManifest.xml



	
		
		
			
				
			
		
	

 

例:跨進程調用Service:

AidlService.java

public class AidlService extends Service
{
	private CatBinder catBinder;
	Timer timer = new Timer();
	String[] colors = new String[]{
		紅色, 
		黃色,
		黑色
	};
	double[] weights = new double[]{
		2.3, 
		3.1,
		1.58
	};
	private String color;
	private double weight;
	// 繼承Stub,也就是實現額ICat接口,並實現了IBinder接口
	public class CatBinder extends Stub
	{
		@Override
		public String getColor() throws RemoteException
		{
			return color;
		}
		@Override
		public double getWeight() throws RemoteException
		{
			return weight;
		}
	}
	@Override
	public void onCreate()
	{
		super.onCreate();
		catBinder = new CatBinder();
		timer.schedule(new TimerTask()
		{
			@Override
			public void run()
			{
				// 隨機地改變Service組件內color、weight屬性的值。
				int rand = (int)(Math.random() * 3);
				color = colors[rand];
				weight = weights[rand];
				System.out.println(-------- + rand);
			}
		} , 0 , 800);
	}
	@Override
	public IBinder onBind(Intent arg0)
	{
		/* 返回catBinder對象
		 * 在綁定本地Service的情況下,該catBinder對象會直接
		 * 傳給客戶端的ServiceConnection對象
		 * 的onServiceConnected方法的第二個參數;
		 * 在綁定遠程Service的情況下,只將catBinder對象的代理
		 * 傳給客戶端的ServiceConnection對象
		 * 的onServiceConnected方法的第二個參數;
		 */
		return catBinder;
	}
	@Override
	public void onDestroy()
	{
		timer.cancel();
	}	
}

 

2.4 客戶端訪問AIDLService

AIDL接口定義了兩個進程間的通信接口,因此客戶端也需要剛才定義的AIDL接口,因此開發客戶端的第一步就是將Service端的AIDL接口文件復制到客戶端應用中。復制到客戶端後ADT工具會為AIDL接口生成相應的實現。

客戶端綁定遠程Service,需要以下兩步:

創建ServiceConnection對象。

以ServiceConnection對象為參數,調用Context的bindService()方法遠程調用Service。

綁定遠程Service的ServiceConnection並不能直接獲取Service的onBind()方法所返回的對象,只能返回onBind()方法所返回的對象的代理。所以, ServiceConnection的on ServiceConnected方法中需要通過如下代碼處理:

 

AidlClient.java

public class AidlClient extends Activity
{
	private ICat catService;
	private Button get;
	EditText color, weight;
	private ServiceConnection conn = new ServiceConnection()
	{
		@Override
		public void onServiceConnected(ComponentName name, IBinder service)
		{
			// 獲取遠程Service的onBind方法返回的對象的代理
			catService = ICat.Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name)
		{
			catService = null;
		}
	};

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		get = (Button) findViewById(R.id.get);
		color = (EditText) findViewById(R.id.color);
		weight = (EditText) findViewById(R.id.weight);
		// 創建所需綁定服務的Intent
		Intent intent = new Intent();
		intent.setAction(com.boby.aidl.action.AIDL_SERVICE);
		// 綁定遠程服務
		bindService(intent, conn, Service.BIND_AUTO_CREATE);
		get.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View arg0)
			{
				try
				{
					// 獲取、並顯示遠程Service的狀態
					color.setText(catService.getColor());
					weight.setText(catService.getWeight() + );
				}
				catch (RemoteException e)
				{
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void onDestroy()
	{
		super.onDestroy();
		// 解除綁定
		this.unbindService(conn);
	}
}

 

電話管理器

電話管理TelephonyManager是一個管理手機通信狀態、電話網絡信息的服務類,該類提供了大量的getXxx()方法來獲取電話網絡的相關信息。

在程序中獲取TelephonyManager,只需調用如下代碼即可:

 

 

例:監聽手機來電:

MonitorPhone.java

public class MonitorPhone extends Activity
{
	TelephonyManager tManager;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 取得TelephonyManager對象 
		tManager = (TelephonyManager) getSystemService
			(Context.TELEPHONY_SERVICE);
		// 創建一個通話狀態監聽器
		PhoneStateListener listener = new PhoneStateListener()
		{
			@Override
			public void onCallStateChanged(int state
				, String incomingNumber)
			{
				switch (state)
				{
					// 無任何狀態
					case TelephonyManager.CALL_STATE_IDLE:
						break;
					case TelephonyManager.CALL_STATE_OFFHOOK:
						break;
					// 來電鈴響時
					case TelephonyManager.CALL_STATE_RINGING:
						OutputStream os = null;
						try
						{
							os = openFileOutput(phoneList, MODE_APPEND);
						}
						catch (FileNotFoundException e)
						{
							e.printStackTrace();
						}
						PrintStream ps = new PrintStream(os);
						// 將來電號碼記錄到文件中
						ps.println(new Date() + 	來電: + incomingNumber);
						ps.close();
						break;
					default:
						break;
				}
				super.onCallStateChanged(state, incomingNumber);
			}
		};
		//監聽電話通話狀態的改變 
		tManager.listen(listener
			, PhoneStateListener.LISTEN_CALL_STATE);
	}
}

注:在DDMS中的File Explorer面板的data/data/com.boby/files目錄下,看到一個phoneList文件,導出該文件,並查看其內容,記錄了來自另一個模擬器的電話呼入。

 

 

短信管理器

SmsManager是Android提供的另一個非常常見的服務, SmsManager提供了系統sendXxxMessage()方法用於發送短信。短信通常是普通的文本內容,也就是調用sendTextMessage()方法進行發送即可。

例:兩個模擬器互發短信:

下面的程序中用到了一個PendingIntent對象,是對Intent的包裝,一般通過調用PendingIntent的getActivity()、getService()、getBroadcastReceiver()靜態方法來獲取PendingIntent對象。

PendingIntent通常會傳給其他應用組件,從而由其他應用程序來執行PendingIntent所包裝的”Intent”。

 

例:

SendSms.java

public class SendSms extends Activity
{
	EditText number , content;
	Button send;
	SmsManager sManager;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 獲取SmsManager
		sManager = SmsManager.getDefault();
		// 獲取程序界面上的兩個文本框和按鈕
		number = (EditText) findViewById(R.id.number);
		content = (EditText) findViewById(R.id.content);
		send = (Button) findViewById(R.id.send);
		// 為send按鈕的單擊事件綁定監聽器
		send.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View arg0)
			{
				// 創建一個PendingIntent對象
				PendingIntent pi = PendingIntent.getActivity(SendSms.this
					, 0, new Intent(), 0);
				// 發送短信
				sManager.sendTextMessage(number.getText().toString()
					, null, content.getText().toString(), pi, null);
				// 提示短信發送完成
				Toast.makeText(SendSms.this
					, 短信發送完成, 8000)
					.show();
			}			
		});
	}
}

 


	


 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved