1. 程式人生 > >Android之四大元件(Service的開啟與關閉)

Android之四大元件(Service的開啟與關閉)

個人開發的微信小程式,目前功能是書籍推薦,後續會完善一些新功能,希望大家多多支援!

前言

服務(Service)是Android系統中的四大元件之一。服務主要用於兩個目的:後臺執行和跨程序訪問。通過啟動

一個服務,可以在不顯示介面的前提下在後臺執行指定的任務,這樣可以不影響使用者做其他事情。通過AIDL服務可以

實現不同程序之間的通訊,這也是服務的重要用途之一。

Service基礎

Service並沒有實際介面,而是一直在Android系統的後臺執行。一般使用Service為應用程式提供一些服務,或不

需要介面的功能,例如下載檔案、播放音訊等。

如何建立與配置Service

在日常開發中Service的建立與配置可以按照以下兩個步驟進行:

(1)定義一個繼承Service的子類。

(2)在AndroidManifest.xml檔案中配置該Service。

Service與Activity一樣,也有一個啟動到銷燬的過程,不過這個過程Service要比Activity簡單多了。一個服務實際

上是一個繼承自android.app.Service的類。檢視Service原始碼,可以看出Service實際上是一個抽象類,在這個抽象類

中有一個抽象方法onBind,因此我們在繼承一個Service類時,必須要實現這個方法。

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
	.......
	public abstract IBinder onBind(Intent intent);
	.......
}

下面類定義了一個Service元件。

public class MyFirstService extends Service{

	public static final String TAG="MyFirstService";
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.e(TAG, "--------onCreate--------");
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.e(TAG, "--------onStartCommand--------");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.e(TAG, "--------onDestroy--------");
	}

}

以上程式碼完成了建立Service,接下來需要在AndroidMainfest.xml檔案中進行配置該Service,以下配置程式碼展示了

如何配置Service:

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name="com.example.servicetest.startservice.MyFirstService" >
        </service>
    </application>

到了這一步我們的Service元件已經建立完畢。接著我們可以啟動Service了,在Android系統中啟動Service有兩種

方式,分別是startService和bindService。

startService使用

下面程式通過兩個按鈕進行啟動與停止Service,演示Service通過startService從建立到銷燬整個過程。

public class MyFirstService extends Service{

	public static final String TAG="MyFirstService";
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.e(TAG, "--------onCreate--------");
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.e(TAG, "--------onStartCommand--------");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.e(TAG, "--------onDestroy--------");
	}

}

兩個按鈕的點選事件:

@Override
public void onClick(View v) {
	switch (v.getId()) {
	case R.id.btn_startService:// startService
		startService(serviceIntent);
		break;
	case R.id.btn_stoptService:// stopService
		stopService(serviceIntent);
		break;
	default:
		break;
      }
}

以上是我們建立的Service元件,接下來對Service進行操作。

(1)當單擊一次啟動(startService)按鈕時:

(2)當服務被啟動後單擊一次停止(stopService)按鈕時:

從上面可以看出Service從建立到銷燬分別經歷了 onCreate---->onStartCommand---->onDestroy

(3)當我們重複開啟Service時:

從上圖可以看出,每當Service被建立時回撥onCreate方法,每次Service被啟動時都會回撥onStartCommand方

法,多次啟動一個已有的Service元件將不會再回調onCreate方法,但每次啟動時都會回撥onStartCommand方法。

其中,當我按下home鍵時,並沒有回撥onDestroy方法,也就是說此Service並沒有隨著Android系統的關閉而關

閉。

bindService的使用

使用startService方法啟動服務,當程式被強制退出時,並且沒有呼叫stopService來停止服務,Service會保持在

後臺一直執行,直到Android系統關閉或呼叫stopService方法後才會停止。如果我們希望在啟動服務的Activity關閉後

服務自動關閉,這就需要將Activity和Service進行繫結。

通過bindService方法可以將Activity和Service繫結。bindService方法的定義如下:

public boolean bindService(Intent service, ServiceConnection conn,int flags) 

該方法的三個引數含義如下:

(1)service:該引數通過Intent指定要啟動的Service。

(2)conn:該引數的型別是ServiceConnection,負責連線Intent物件指定的服務。當訪問者與Service之間連線

成功時將回調ServiceConnecttion物件的onServiceConnected(ComponentName name,IBinder service)方法;當

Service所在的宿主程序由於異常終止或由於其他原因終止,導致該Service與訪問者之間斷開連線時回撥

ServiceConnection物件的onServiceDisconnected(ComponentName name)方法。

(3)flags:該引數是一個標誌位,一般設為Context.BIND_AUTO_CREATE。

以下建立了一個繼承Service的類,在該類中增加了幾個與繫結相關的事件方法:
 

public class MyFirstService extends Service{
	
	private String info;
	private MyBinder myBinder=new MyBinder();

	public static final String TAG="MyFirstService";

	/**
	 * 重新繫結時呼叫該方法
	 */
	@Override
	public void onRebind(Intent intent) {
		super.onRebind(intent);
	}
	
	/**
	 * 解除繫結時呼叫該方法
	 */
	@Override
	public boolean onUnbind(Intent intent) {
		return super.onUnbind(intent);
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return myBinder;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.e(TAG, "--------onCreate--------");
		info="onCreate";
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.e(TAG, "--------onStartCommand--------");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.e(TAG, "--------onDestroy--------");
	}
	
	public class MyBinder extends Binder{
		public String getInfo(){
			return info;
		}
	}

}
public class MainActivity extends Activity implements OnClickListener {

	private Button btn_startService;
	private Button btn_stopService;
	private Button btn_bindService;
	private Button btn_unbindService;
	private Button btn_getinfo;

	private Intent serviceIntent;

	private MyFirstService.MyBinder myBinder;

	private ServiceConnection conn = new ServiceConnection() {

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

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.e(MyFirstService.TAG, "------onServiceConnected---------");
			myBinder = (MyFirstService.MyBinder) service;
		}
	};

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

	private void initData() {
		serviceIntent = new Intent(this, MyFirstService.class);
	}

	private void initView() {
		btn_startService = (Button) this.findViewById(R.id.btn_startService);
		btn_stopService = (Button) this.findViewById(R.id.btn_stoptService);
		btn_bindService = (Button) this.findViewById(R.id.btn_bindService);
		btn_unbindService = (Button) this.findViewById(R.id.btn_unbindService);
		btn_getinfo = (Button) this.findViewById(R.id.btn_getinfo);
	}

	private void initEvent() {
		btn_startService.setOnClickListener(this);
		btn_stopService.setOnClickListener(this);
		btn_bindService.setOnClickListener(this);
		btn_unbindService.setOnClickListener(this);
		btn_getinfo.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn_startService:// startService
			startService(serviceIntent);
			break;
		case R.id.btn_stoptService:// stopService
			stopService(serviceIntent);
			break;
		case R.id.btn_bindService:// bindService
			bindService(serviceIntent, conn, Service.BIND_AUTO_CREATE);
			break;
		case R.id.btn_unbindService:// unbindService
			unbindService(conn);
			break;
		case R.id.btn_getinfo:// 獲取資料
			Toast.makeText(MainActivity.this, myBinder.getInfo(),
					Toast.LENGTH_SHORT).show();
			break;
		default:
			break;
		}
	}

}

執行效果:

在MyFirstService類中定義了一個MyBinder類,該類用於獲取一個String型別的返回值,

ServiceConnection.onServiceConnected方法的第2個引數是一個IBinder型別的變數,將該引數轉換成

MyFirstService.MyBinder物件,並使用myBinder.getInfo()方法獲取String型別的值。

接著看下我們是如何使用bindService和unbindService操作的。

(1)當我們單擊一次bindService(bindService(service,conn,flags))按鈕時:

(2)當我們單擊一次unbindService按鈕時:

從上面可以看出通過bindService開啟服務,再通過unbindService停止服務的過程是 onCreate------>onBind------

->onServiceConnected------->onUnbind------>onDestory

這裡面值得注意的是,當我按下home鍵時,此時並沒有呼叫unbindService方法進行停止服務,但依然能打印出

onUnbind---->onDestory,也就是說通過bindService開啟的服務是隨著Activity的銷燬而銷燬。

Service的生命週期

下圖的左半部分是通過startService()方法啟動時的Service生命週期,右半部分是通過bindService()方法啟動時

的Service生命週期。

Service生命週期有一種特殊的情形,如果Service已由某個客戶端通過startService()方法啟動了,接下來其他客

戶端再呼叫bindService()方法來繫結該Service後,再呼叫unbindService()方法解除繫結,最後又呼叫了bindService()

方法再次繫結到Service,這個過程所觸發的生命週期如下:

進行拆解步驟:

(1)呼叫startService時的生命週期:onCreate------>onStartCommand

(2)呼叫bindService時的生命週期:onBind------>onServiceConnected

(3)呼叫unbindService時的生命週期:onUnbind

(4)再一次呼叫bindService時的生命週期:onServiceConnected----->onRebind

以上呼叫unbindService時,並沒有回撥onDestroy()方法,這是因為該Service並不是由Activity通過bindService()

方法來啟動的,因此當Activity呼叫unbindService()方法取消與該Activity的繫結時,該Service也不會終止。當Activity

呼叫bindService()繫結一個已經啟動的Service時,系統只是把Service內部IBinder物件傳給Activity,當Activity呼叫

unbindService()方法取消與該Service的繫結時,只是切斷了Activity與Service之間的聯絡,並不能停止Service元件。

-------------------------------------------------------------------------------------------------------------------------------------------------------