鍥而舍之,朽木不折;鍥而不捨,金石可鏤。——荀況
今天學習了一下Service的用法就和大家一起來討論Android中Service的相關知識點,如有謬誤,歡迎批評指正,如有疑問歡迎留言。
一、Service用途
Service在Android中和Activity是屬於同一級別上的組件,Android中的Service,其意思是“服務”,它在後臺運行不可交互。Service自己不能運行,需要通過某一個Activity或者其它Context對象來調用,Context.startService()和Context.bindService()兩種方式啓動
Service 。
Android 中的服務,它與 Activity不同,它是不能與用戶交互的,不能自己啓動的,運行在後臺的程序(幹着重的工作,卻連個界面也沒有,因此我說它低調),那我們什麼時候會用到Service呢?比如我們播放音樂的時候,有可能想邊聽音樂邊幹些其他事情,當我們退出播放音樂的應用,如果不用 Service,我們就聽不到歌了,所以這時候就得用到Service了,又比如當我們一個應用的數據是通過網絡獲取的,不同時間(一段時間)的數據是不同的,這時候我們可以用 Service在後臺定時更新,而不用每打開應用的時候在去獲取。如果在
Service的onCreate或者 onStart方法中做一些很耗時的動作,最好是啓動一個新線程來運行這個 Service,因爲,如果 Service運行在主線程中,會影響到程序的 UI操作或者阻塞主線程中的其它事情。
二、Service的生命週期
首先來看官網給出的Service的生命週期圖
2.onStart(Intent intent, int startId) 啓動Service
4.onDestroy() 銷燬Service
5.onBind() 返回一個IBinder接口對象給Service
package com.example.servicepractice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "MyService";
@Override
public void onCreate() {
super.onCreate();
Log. i(TAG,"onCreate called" );
}
@Override
public void onStart(Intent intent, int startId) {
super. onStart(intent, startId);
Log. i(TAG,"onStart called" );
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log. i(TAG,"onStartCommand called" );
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log. i(TAG,"onDestroy called" );
}
@Override
public IBinder onBind(Intent intent) {
Log. i(TAG,"onBind called" );
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log. i(TAG,"onUnbind called" );
return super.onUnbind(intent);
}
}
2.MainActivity的代碼package com.example.servicepractice;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
public class MainActivity extends Activity {
protected static final String TAG = "MyService";
private Button btn_start;
private Button btn_stop;
private Button btn_bind;
private Button btn_unbind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout. activity_main);
findViews();
setClick();
}
private void findViews() {
btn_start=(Button) findViewById(R.id. btn_start);
btn_stop=(Button) findViewById(R.id. btn_stop);
btn_bind=(Button) findViewById(R.id. btn_bind);
btn_unbind=(Button) findViewById(R.id. btn_unbind);
}
private void setClick() {
//採用startService啓動服務
btn_start.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent= new Intent(MainActivity.this,MyService.class );
startService(intent);
}
});
//銷燬服務
btn_stop.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent= new Intent(MainActivity.this,MyService.class );
stopService(intent);
}
});
//綁定服務
btn_bind.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MyService.class );
bindService(intent, conn,Context. BIND_AUTO_CREATE);
}
});
//解除綁定
btn_unbind.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
unbindService( conn);
}
});
}
private ServiceConnection conn=new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
//connected
Log. i(TAG,"onServiceConnection called." );
}
public void onServiceDisconnected(ComponentName name) {
}
};
}
<service
android:name="com.example.servicepractice.MyService" >
<intent-filter>
<action android:name="com.example.service" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
//採用startService啓動服務
btn_start.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent= new Intent(MainActivity.this,MyService.class );
startService(intent);
}
});
//銷燬服務
btn_stop.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this,MyService. class);
stopService(intent);
}
});
首先我們點擊啓動按鈕打印日誌如下
我們發現再次啓動時系統並沒有重新實例化這個Service,因爲系統發現這個服務已經啓動了,此時它會直接調用onStartCommand方法,在onStartCommand方法中會調用onStart方法
onStartCommand方法的源碼:
/* @param intent The Intent supplied to {@link android.content.Context#startService},
* as given. This may be null if the service is being restarted after
* its process has gone away, and it had previously returned anything
* except {@link #START_STICKY_COMPATIBILITY}.
* @param flags Additional data about this start request. Currently either
* 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
* @param startId A unique integer representing this specific request to
* start. Use with {@link #stopSelfResult(int)}.
*
* @return The return value indicates what semantics the system should
* use for the service's current started state. It may be one of the
* constants associated with the {@link #START_CONTINUATION_MASK} bits.
*
* @see #stopSelfResult(int)
*/
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent , startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
操作完啓動服務按鈕後我們接着點擊銷燬服務按鈕打印日誌如下發現當調用 stopService(intent)這個方法是會調用Service的onDestroy方法從而銷燬服務。
2."綁定服務"和"解除綁定"的學習
//綁定服務
btn_bind.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MyService.class );
bindService(intent, conn,Context. BIND_AUTO_CREATE);
}
});
//解除綁定
btn_unbind.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
unbindService( conn);
}
});
private ServiceConnection conn= new ServiceConnection() {
/**
* Called when a connection to the Service has been established, with
* the {@link android.os.IBinder} of the communication channel to the
* Service.
*
* @param name The concrete component name of the service that has
* been connected.
*
* @param service The IBinder of the Service's communication channel,
* which you can now make calls on.
*/
public void onServiceConnected(ComponentName name, IBinder service) {
//connected
Log. i( TAG,"onServiceConnection called." );
}
/**
* Called when a connection to the Service has been lost. This typically
* happens when the process hosting the service has crashed or been killed.
* This does <em>not </em> remove the ServiceConnection itself -- this
* binding to the service will remain active, and you will receive a call
* to {@link #onServiceConnected} when the Service is next running.
*
* @param name The concrete component name of the service whose
* connection has been lost.
*/
public void onServiceDisconnected(ComponentName name) {
}
};
到這我們還差一步就可以綁定服務了,因爲在前面服務中的onBind方法返回值爲null,這樣是不行的,要想實現綁定操作,必須返回一個實現了IBinder接口類型的實例,該接口描述了與遠程對象進行交互的抽象協議,有了它我們才能與服務進行交互。所以我們要修改代碼 @Override
public IBinder onBind(Intent intent) {
Log. i(TAG,"onBind called" );
return new Binder(){};
}
//定義一個變量,標識這個服務是否處於綁定狀態
private boolean binded;
//定義一個綁定服務的方法
private void unbindService(){
if( binded){
unbindService( conn);
binded= false;
}
}
//解除綁定
btn_unbind.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
unbindService();
}
});
//在onDestroy方法中調用解除綁定的方法
protected void onDestroy() {
unbindService();
};
這樣上面兩種錯誤就解決了,也體現了我們寫代碼的嚴謹性。1、在調用 bindService 綁定到Service的時候,你就應當保證在某處調用 unbindService 解除綁定(儘管 Activity 被 finish 的時候綁定會自動解除,並且Service會自動停止);
2、在使用 startService 啓動服務之後,一定要使用 stopService停止服務,不管你是否使用bindService;
3、同時使用 startService 與 bindService 要注意到,Service 的終止,需要unbindService與stopService同時調用,才能終止 Service,不管 startService 與 bindService 的調用順序,如果先調用 unbindService 此時服務不會自動終止,再調用 stopService 之後服務纔會停止,如果先調用 stopService 此時服務也不會終止,而再調用 unbindService 或者 之前調用 bindService 的 Context 不存在了(如Activity 被 finish 的時候)之後服務纔會自動停止;
4、當在旋轉手機屏幕的時候,當手機屏幕在“橫”“豎”變換時,此時如果你的Activity 如果會自動旋轉的話,旋轉其實是 Activity 的重新創建,因此旋轉之前的使用 bindService 建立的連接便會斷開(Context 不存在了),對應服務的生命週期與上述相同。
5、在 sdk 2.0 及其以後的版本中,對應的 onStart 已經被否決變爲了 onStartCommand,不過之前的 onStart 任然有效。這意味着,如果你開發的應用程序用的 sdk 爲 2.0 及其以後的版本,那麼你應當使用 onStartCommand 而不是 onStart。
6、startService 啓動服務想要用startService啓動服務,不管Local (本地)還是 Remote(遠程) 我們需要做的工作都是一樣簡單。當然要記得在Androidmanifest.xml 中註冊 service。
好了這一篇就到這裏了,歡迎大家留言交流,批評指正。