天天看點

android應用層服務——binderService與StartService

          android中應用層的服務級别與activity差不多。service都是運作在背景的服務,那麼它就是不可見的,沒有界面的東西。你可以啟動一個服務Service來播放音樂,或者記錄你地理資訊位置的改變,或者啟動一個服務來運作并一直監聽某種動作。

          Service和其他元件一樣,都是運作在主線程中,是以不能用它來做耗時的請求或者動作。你可以在服務中開一一個線程,線上程中做耗時動作。

一.基礎知識

服務一般分為兩種:

1:本地服務, Local Service 用于應用程式内部。在Service可以調用Context.startService()啟動,調用Context.stopService()結束。在内部可以調用Service.stopSelf() 或 Service.stopSelfResult()來自己停止。無論調用了多少次startService(),都隻需調用一次stopService()來停止。

2:遠端服務, Remote Service 用于android系統内部的應用程式之間。可以定義接口并把接口暴露出來,以便其他應用進行操作。用戶端建立到服務對象的連接配接,并通過那個連接配接來調用服務。調用Context.bindService()方法建立連接配接,并啟動,以調用 Context.unbindService()關閉連接配接。多個用戶端可以綁定至同一個服務。如果服務此時還沒有加載,bindService()會先加載它。提供給可被其他應用複用,比如定義一個天氣預報服務,提供與其他應用調用即可。

3、生命周期

context.startService() ->onCreate()- >onStart()->Service running--調用context.stopService() ->onDestroy()

context.bindService()->onCreate()->onBind()->Service running--調用>onUnbind() ->onDestroy()

二.本地服務示範

1、startService的demo

(1)服務端

package com.example.localserver;

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

public class DataService extends Service {
	public static final String TAG = "LocalService";

	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	}

	@Override
	public void onStart(Intent intent, int startId) {
		Log.d(TAG, "onStart");
		super.onStart(intent, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		return null;
	}

}
           

(2)用戶端

package com.example.localserver;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	public static final String TAG = "MainActivity";

	private Button mbtn1;
	private Button mbtn2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mbtn1 = (Button) findViewById(R.id.start_service);
		mbtn2 = (Button) findViewById(R.id.stop_service);

		mbtn1.setOnClickListener(this);
		mbtn2.setOnClickListener(this);

	}

	@Override
	public void onClick(View v) {
		Intent mIntent = new Intent(this, DataService.class);
		switch (v.getId()) {
		case R.id.start_service:
			Log.d(TAG, "click Start Service button");

			startService(mIntent);
			break;
		case R.id.stop_service:
			Log.d(TAG, "click Stop Service button");

			stopService(mIntent);
			break;

		default:
			break;

		}
	}

	@Override
	public 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;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

}
           

【實驗結果】

06-10 05:56:54.182: D/MainActivity(2084): click Start Service button

06-10 05:56:54.216: D/LocalService(2084): onCreate

06-10 05:56:54.228: D/LocalService(2084): onStartCommand

06-10 05:56:54.228: D/LocalService(2084): onStart

06-10 05:57:08.123: D/MainActivity(2084): click Start Service button

06-10 05:57:08.186: D/LocalService(2084): onStartCommand

06-10 05:57:08.186: D/LocalService(2084): onStart

06-10 05:57:13.865: D/MainActivity(2084): click Stop Service button

06-10 05:57:13.880: D/LocalService(2084): onDestroy

【分析】

startService的特點是activity與service沒有共存亡,當退出activity時,service仍在背景運作,是以,當再次進入activity時,點選開始按鈕,就沒有再使用onCreate方法了,而是直接調用onStartCommand方法。

2、bindService的demo

          bindservice實作的關鍵之處,在于 onBind(Intent) 這個方法 傳回了一個實作了 IBinder 接口的對象,這個對象将用于綁定 Activity 與 Service 通信。

【實作方法】

(1)Service中,建立一個 Binder實體,重載onBind(Intent intent)方法,傳回Binder執行個體給Activity,然後執行onCreate()函數。

(2)Activity中,通過private ServiceConnection sc = new ServiceConnection() 建立一個Service連接配接,onServiceConnected()擷取Service執行個體,onServiceDisconnected()釋放連接配接;并通過IBinder接口,調用service中的方法。

(3)Activity中,Intent intent = new Intent("******"); 建構一個service的action,然後bindService(intent, sc, BIND_AUTO_CREATE)綁定服務

【demo】

(1)service端

package com.example.localserver;

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

public class DataService extends Service {
	public static final String TAG = "LocalService";
	private DataDownloadBinder mBinder = new DataDownloadBinder(); 
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		return mBinder;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(TAG, "onUnbind");
		return super.onUnbind(intent);
	}
}
           
package com.example.localserver;

import android.os.Binder;
import android.util.Log;

public class DataDownloadBinder extends Binder{
	
	public static final String TAG = "Binder";
	public void startDownload() {
		Log.d(TAG, "startDownload() executed");
	}

	public int add(int a, int b) {
		Log.d(TAG, "add() executed");
		return a + b;
	}
	// 執行具體的下載下傳任務
}
           

(2)clinet端

package com.example.localserver;

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.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	public static final String TAG = "MainActivity";

	private Button mbtn1;
	private Button mbtn2;
	private Button mbtn3;
	private Button mbtn4;

	private DataDownloadBinder mbinder;

	private ServiceConnection mServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mbinder = (DataDownloadBinder) service;
			mbinder.startDownload();
			int sum = mbinder.add(3, 5);
			Log.d(TAG, "sum = " + sum);
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mbtn1 = (Button) findViewById(R.id.start_service);
		mbtn2 = (Button) findViewById(R.id.stop_service);
		mbtn3 = (Button) findViewById(R.id.bind_service);
		mbtn4 = (Button) findViewById(R.id.unbind_service);

		mbtn1.setOnClickListener(this);
		mbtn2.setOnClickListener(this);
		mbtn3.setOnClickListener(this);
		mbtn4.setOnClickListener(this);

	}

	@Override
	public void onClick(View v) {
		Intent mIntent = new Intent(this, DataService.class);
		switch (v.getId()) {
		case R.id.start_service:
			Log.d(TAG, "click Start Service button");
			startService(mIntent);
			break;
		case R.id.stop_service:
			Log.d(TAG, "click Stop Service button");
			stopService(mIntent);
			break;
		case R.id.bind_service:
			bindService(mIntent, mServiceConnection, BIND_AUTO_CREATE);
			break;
		case R.id.unbind_service:
			unbindService(mServiceConnection);
			break;
		default:
			break;

		}
	}

	@Override
	public 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;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

}
           

【實驗結果】

06-10 06:03:27.322: D/MainActivity(2195): click Start Service button

06-10 06:03:27.376: D/LocalService(2195): onCreate

06-10 06:03:27.388: D/LocalService(2195): onStartCommand

06-10 06:03:27.388: D/LocalService(2195): onStart

06-10 06:03:39.088: D/LocalService(2195): onBind

06-10 06:03:39.132: D/Binder(2195): startDownload() executed

06-10 06:03:39.132: D/Binder(2195): add() executed

06-10 06:03:39.132: D/MainActivity(2195): sum = 8

06-10 06:03:52.363: D/LocalService(2195): onUnbind

06-10 06:04:08.229: D/MainActivity(2195): click Start Service button

06-10 06:04:08.243: D/LocalService(2195): onStartCommand

06-10 06:04:08.243: D/LocalService(2195): onStart

06-10 06:04:19.284: D/MainActivity(2195): click Stop Service button

06-10 06:04:19.307: D/LocalService(2195): onDestroy

三、遠端服務示範

需要使用aidl與bindService共同實作遠端服務。

(1)client

package com.example.client;

import com.example.service.ICom;

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.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {
	private static final String TAG = "Client";
	private ICom mICom;

	private Button mbtn1;
	private Button mbtn2;
	private TextView mTV;
	private String url;
	private boolean isBind = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mbtn1 = (Button) findViewById(R.id.btn_bind);
		mbtn2 = (Button) findViewById(R.id.btn_allinfo);
		mbtn2.setOnClickListener(this);
		mbtn1.setOnClickListener(this);

		mTV = (TextView) findViewById(R.id.textView);
	}

	ServiceConnection mSC = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			Log.d(TAG, "onServiceDisconnected...");
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.d(TAG, "Client onServiceConnected");
			mICom = ICom.Stub.asInterface(service);
			if (mICom == null) {
				Log.d(TAG, "Failed");
			} else {
				isBind = true;
				mbtn1.setText("斷開");
				mTV.setText("已連接配接");
				try {
					url = mICom.getWebSite();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		}
	};

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn_bind:
			if (isBind == false) {
				Intent mIntent = new Intent();
				mIntent.setAction("com.example.remote");
				mIntent.setPackage("com.example.service");
				mbtn2.setEnabled(true);
				bindService(mIntent, mSC, Context.BIND_AUTO_CREATE);
			} else {
				mbtn2.setEnabled(false);
				mbtn1.setText("連接配接");
				isBind = false;
				mTV.setText("已斷開連接配接!");
				unbindService(mSC);
			}
			break;
		case R.id.btn_allinfo:
			mTV.setText(url);
			break;

		default:
			break;
		}
	}
}
           

(2)server

package com.example.service;

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

public class RemoteService extends Service {
	private static final String TAG = "Remote Service";
	private Com mtest = new Com();

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		Log.d(TAG, "Oncreate");
		super.onCreate();
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		Log.d(TAG, "OnDestroy");
		super.onDestroy();
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		return mtest;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(TAG, "onUnbind");
		return super.onUnbind(intent);
	}

	private class Com extends ICom.Stub {

		@Override
		public String getWebSite() throws RemoteException {
			String url = "www.baidu.com";
			return url;
		}
	}

}
           

(3)aidl檔案

package com.example.service;

interface ICom{
	String getWebSite();
}