Service簡單概述
Service(服務):是一個沒有用戶界面、可以在后台長期運行且可以執行操作的應用組件。服務可由其他應用組件啟動(如:Activity、另一個service)。此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。例如:服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而這一切均可在后台進行。
進程的優先級
了解進程的優先級可以幫助你理解服務~
-
1. Foreground process(前台進程)
- 一句話總結:當前跟用戶有交互的進程就是前台進程。
-
2. Visible process(可見進程)
- 相當於Activity的onPause方法執行。如:Activity彈出Dialog時。
-
3. Service process(服務進程)
- 相當於使用startService開啟一個服務,雖然做的事情用戶看不到,但是又是用戶所關心的事情。如:后台播放音樂,下載數據等。
-
4. Background process(后台進程)
- 相當於Activity的onStop方法被執行。如:按Home鍵退出應用。
-
5. Empty process(空進程)
- 應用程序沒有任何的組件在活動,該應用就是一個空進程。唯一存活的原因就是為了提高下次開啟的時間。
開啟服務的兩種方式
服務:默認運行在主線程。
服務的創建流程
- 自定義一個服務類繼承 android.app.Service;
- 在清單文件中配置 service(AndroidManifest.xml);
- 在服務類中重寫方法。
<service android:name=".service.MyCustomService"></service>
服務的兩種開啟方式
一:start 方式
先上代碼
private Intent startIntent;
//start方式:開啟服務
public void startOpenService(View v) {
//創建一個開啟服務的Intent對象
startIntent = new Intent(this, MyCustomService.class);
this.startService(startIntent); //開啟一個服務
}
//start方式:關閉服務
public void startCloseService(View v) {
if (startIntent != null) {
this.stopService(startIntent);
startIntent = null;
}
}
1. 通過 startService(Intent service)開啟服務
- onCreate()、onStartCommand() 兩個方法在服務第一次開啟的時候會被依次執行。
- 當服務開啟之后,再點擊開啟服務,只會執行onStartCommand()方法。
2. 通過 stopService(Intent service)關閉服務
- onDestroy() 方法會在執行 stopService 方法(關閉服務)的時候,被執行!
- 注意參數:Intent對象不能為null,要先進行判空(不為null的情況下,可以多次調用)。
特別說明
1. stopService傳入的Intent對象,必須和startService傳入的Intent對象是同一個對象,才能保證開啟的服務被關閉。
2. 應用退出后(應用在后台運作,未被殺死),服務依然會運行中。
3. 當手動殺掉應用進程后,服務將會終止!且該方式不會執行服務的onDestroy()方法。
二:bind 方式
先上代碼
private Intent bindIntent;
private MyServiceConnection connection;
private boolean isSuccess;
//bind方式:開啟服務
public void bindOpenService(View v) {
if (!isSuccess) {
bindIntent = new Intent(this, MyCustomService.class);
//boolean bindService(Intent service, //開啟服務的意圖對象
// ServiceConnection conn, //服務連接對象
// int flags) //綁定服務操作選項()
connection = new MyServiceConnection();
isSuccess = this.bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
}
}
//bind方式:解綁服務
public void bindCloseService(View v) {
//void unbindService(ServiceConnection conn)
if (connection != null) {
this.unbindService(connection);
connection = null;
isSuccess = false;
}
}
1. 通過 bindService() 開啟服務
- onCreate()、onBind() 兩個方法在服務第一次開啟的時候,被依次執行。
- 再次操作bindService的話,不會有什么方法被執行。若要使用該方式開啟服務的話,建議獲取綁定后的狀態,若成功則不再操作綁定。
2. 通過 unbindService() 解綁服務
- onUnbind()、onDestroy() 兩個方法會在執行服務解綁 unbindService 方法的時候,被依次執行。所以解綁只能操作一次。
特別說明
1. 綁定和解綁傳遞的ServiceConnection對象要保證是同一個對象!
2. isSuccess存儲服務綁定成功(true)的狀態,當綁定成功之后,避免重復的綁定。因為每次bindService傳遞的ServiceConnection對象都是new的新對象,unbindService傳遞的ServiceConnection對象可能會與服務綁定時傳遞的對象不一致,就會拋出異常!
3. 解綁之后,isSuccess賦值false,就可以再次操作綁定了。
4. bind方式開啟的服務是一個隱形的服務,在設置中無法找到(其實現在有些手機定制系統,start方式開啟的服務也成了一個隱形服務了)。
5. bind方式開啟服務與開啟者(Activity),存在着依附關系,在開啟者被銷毀前,必須解綁bind方式開啟的服務,不然會拋出異常!(不求同生,但求同死。)
服務模板代碼
需求:在Activity中,使用 bind方式 啟動一個服務,並調用服務中的方法(模擬一些業務處理)。
分析:流程步驟
- 創建一個服務類,繼承 Service。如:MyCustomService;
- 自定義一個服務接口對象類,實現ServiceConnection接口。如:MyServiceConnection;
- 自定義一個中間幫助類,繼承Binder類(IBinder實現類)。當服務中的onBind方法被執行的時候,作為返回值。如:MyBinderImpl;
- 自定義一個接口,封裝一些中間幫助類對象共有的函數。如:MyBinderInterface。
整個流程代碼如下
MyCustomService.class
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
/**
* 創建一個服務類
*/
public class MyCustomService extends Service {
@Override
public IBinder onBind(Intent intent) {
//該方法:在使用【bind綁定】的方式:開啟服務的時候,才會被調用
Log.e("Service生命周期", "【onBind】");
//返回值需要一個IBinder接口實現類對象(可以返回自定義實現類對象)
return new MyBinderInter();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("Service生命周期", "【onUnbind】");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
super.onCreate();
//服務第一次創建時調用
Log.e("Service生命周期", "【onCreate】");
//獲取服務運行線程
String name = Thread.currentThread().getName();
long id = Thread.currentThread().getId();
Log.e("線程", "【Service】" + name + "-" + id);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//每次開啟服務(Activity內調用startService()方法)時調用
Log.e("Service生命周期", "【onStartCommand】");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
//服務被銷毀時調用
Log.e("Service生命周期", "【onDestroy】");
}
//模擬:定義一些函數,作為業務處理
public void playPoker() {
Toast.makeText(this, "玩撲克", Toast.LENGTH_SHORT).show();
}
public void playBall() {
Toast.makeText(this, "打球", Toast.LENGTH_SHORT).show();
}
/**
* 中間幫助類:自定義類繼承 Binder(IBinder 接口實現類)
*/
public class MyBinderInter extends Binder implements MyBinderInterface {
@Override
public void callPlayPoker() {
playPoker();
}
@Override
public void callPlayBall() {
playBall();
}
}
}
MyServiceConnection.class
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
/**
* 創建一個服務接口對象類:當服務綁定成功時,可以接收一個中間幫助類對象
* 當 MyCustomService 中的 onBind 方法返回值不為null時,該服務連接對象類中的方法才會被執行
*/
public class MyServiceConnection implements ServiceConnection {
private MyCustomService.MyBinderInter myBinderInter;
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//服務綁定成功后執行(onBind執行后執行該方法) IBinder:中間幫助類對象
this.myBinderInter = (MyCustomService.MyBinderInter) iBinder;
Log.e("Service生命周期", "【onServiceConnected】");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//該方法在連接正常關閉的情況下不會被執行,只有在Service被破壞或殺死的情況下執行。
//如:系統資源不足,需要殺掉該服務,則會執行該方法。
}
public void callPlayPoker(){
if(myBinderInter!=null){
myBinderInter.callPlayPoker();
}
}
public void callPlayBall(){
if(myBinderInter!=null){
myBinderInter.callPlayBall();
}
}
}
接口:MyBinderInterface
//自定義接口:封裝中間幫助類所共有的一些方法
public interface MyBinderInterface {
//隨意定義兩個抽象方法,由實現類重寫
void callPlayPoker();
void callPlayBall();
}
ServiceActivity 內調用服務內的方法
- 切記:在activity執行onDestroy()方法的時候,解綁服務,否則會拋出異常。
public class ServiceActivity extends BaseActivity {
private Intent bindIntent;
private MyServiceConnection connection;
private boolean isSuccess;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
}
//bind方式:開啟服務
public void bindOpenService(View v) {
if (!isSuccess) {
bindIntent = new Intent(this, MyCustomService.class);
connection = new MyServiceConnection();
isSuccess = this.bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
}
}
public void playPoker(View v) {
if (connection != null) {
connection.callPlayPoker();
}
}
public void playBall(View v) {
if (connection != null) {
connection.callPlayBall();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (connection != null) {
this.unbindService(connection);
connection = null;
isSuccess = false;
}
}
}
關於:bindService和unbindService的源碼說明(英文好的小伙伴可以一起學習)
boolean bindService (Intent service, ServiceConnection conn, int flags)
- 方法說明
Connect to an application service, creating it if needed. This defines a dependency between your application and the service. The given conn will receive the service object when it is created and be told if it dies and restarts. The service will be considered required by the system only for as long as the calling context exists. For example, if this Context is an Activity that is stopped, the service will not be required to continue running until the Activity is resumed.
This function will throw SecurityException if you do not have permission to bind to the given service.
Note: this method can not be called from a BroadcastReceiver component. A pattern you can use to communicate from a BroadcastReceiver to a Service is to call startService(Intent) with the arguments containing the command to be sent, with the service calling its stopSelf(int) method when done executing that command. See the API demo App/Service/Service Start Arguments Controller for an illustration of this. It is okay, however, to use this method from a BroadcastReceiver that has been registered with registerReceiver(BroadcastReceiver, IntentFilter), since the lifetime of this BroadcastReceiver is tied to another object (the one that registered it). - Parameters(參數說明)
service:Identifies the service to connect to. The Intent may specify either an explicit component name, or a logical description (action, category, etc) to match an IntentFilter published by a service.
conn:Receives information as the service is started and stopped. This must be a valid ServiceConnection object; it must not be null.
flags:Operation options for the binding. May be 0, BIND_AUTO_CREATE, BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND, BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, or BIND_WAIVE_PRIORITY. - Returns(返回值說明)
If you have successfully bound to the service, true is returned; false is returned if the connection is not made so you will not receive the service object.
void unbindService (ServiceConnection conn)
- 方法說明
Disconnect from an application service. You will no longer receive calls as the service is restarted, and the service is now allowed to stop at any time. - Parameters(參數說明)
conn:The connection interface previously supplied to bindService(). This parameter must not be null.
參考鏈接:Google官方文檔:Service
PS:期待與大家有更多的交流,謝謝~