Android中Service的一些總結

關於Service

Service 是一個可以在後臺執行長時間運行操作而不提供用戶界面的應用組件。服務可由其他應用組件啓動,而且即使用戶切換到其他應用,服務仍將在後臺繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而所有這一切均可在後臺進行。

Service分類

Service的工作狀態分爲兩種類型:

啓動:主要用於執行後臺計算。
綁定:主要用於其他組件和Service進行交互。

注意: 服務在其託管進程的主線程中運行,它既不創建自己的線程,也不再單獨的進程中運行(除非另行指定)。這意味着,如果服務將執行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或聯網),則應在服務內創建新線程來完成這項工作。通過使用單獨的線程,可以降低發生“應用無響應”(ANR) 錯誤的風險,而應用的主線程仍可繼續專注於運行用戶與 Activity 之間的交互。

創建Service

創建Service時必須重寫它的幾個回調方法,案例如下:

public class CustomService extends Service{

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

        @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

回調方法說明:

  • onCreate()

    首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。如果服務已在運行,則不會調用此方法。

  • onStartCommand()

    當另一個組件(如 Activity)通過調用 startService() 請求啓動服務時,系統將調用此方法。一旦執行此方法,服務即會啓動並可在後臺無限期運行。 如果您實現此方法,則在服務工作完成後,需要由您通過調用 stopSelf() 或 stopService() 來停止服務。(如果您只想提供綁定,則無需實現此方法。)

  • onBind()

    當另一個組件想通過調用 bindService() 與服務綁定(例如執行 RPC)時,系統將調用此方法。在此方法的實現中,您必須通過返回 IBinder 提供一個接口,供客戶端用來與服務進行通信。請務必實現此方法,但如果您並不希望允許綁定,則應返回 null。

  • onUnbind()

    當前Service被解綁時,系統將調用此方法。

  • onDestroy()

    當服務不再使用且將被銷燬時,系統將調用此方法。服務應該實現此方法來清理所有資源,如線程、註冊的偵聽器、接收器等。 這是服務接收的最後一個調用。

AndroidManifest.xml配置

Service與其他組件(如:Activity)一樣都需要在AndroidManifest進行註冊,

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample.app">

    <application
        ......

        <!--註冊Service-->
        <service
            android:name=".CustomService"
            android:exported="false" />
    </application>

</manifest>

android:name 屬性是唯一必需的屬性,用於指定服務的類名。
android:exported 屬性並將其設置爲 “false”,確保服務僅適用於您的應用。這可以有效阻止其他應用啓動您的服務。

啓動Service

調用 startService() 啓動Service

Intent mIntent = new Intent(this, CustomService.class)
startService(mIntent);

停止Service

stopService(new Intent(this, CustomService.class));

通過 startService() 啓動該Service,從啓動到停止Log輸出如下:

03-16 10:38:12.959 21096-21096/com.sample.app E/CustomService: ----- onCreate() 
03-16 10:38:12.960 21096-21096/com.sample.app E/CustomService: ----- onStartCommand()  
03-16 10:38:15.192 21096-21096/com.sample.app E/CustomService: ----- onDestroy()

綁定Service

調用 bindService() 綁定一個Service,定義Service代碼如下:

public class CustomService extends Service {

    private static final String TAG = CustomService.class.getSimpleName();

    @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 boolean onUnbind(Intent intent) {
        Log.e(TAG, "----- onUnbind()");
        return super.onUnbind(intent);
    }

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "----- onBind()");
        return new CustomBind();
    }

    class CustomBind extends Binder {

        public CustomService getService() {
            return CustomService.this;
        }
    }
}

通過 bindService() 綁定一個Service時,需要定義一個 Binder 的子類,如上面代碼中:

class CustomBind extends Binder {

    public CustomService getService() {
        return CustomService.this;
    }
}

這樣就可以拿到一個Service對象,在Activity中通過ServiceConnection接口來取得建立連接與連接意外丟失的回調

public class BindServiceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 通過bindService綁定Service
        Intent mIntent = new Intent(this, CustomService.class);
        bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Activity銷燬時解綁Service
        unbindService(mServiceConnection);
    }

    // 在Activity中,我們通過ServiceConnection接口來取得建立連接與連接意外丟失的回調
    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 建立連接,獲取服務的操作對象
            CustomService.CustomBind mBind = (CustomService.CustomBind) service;
            mBind.getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 連接斷開
        }
    };
}

解綁Service

unbindService(mServiceConnection);

該Activity由創建到銷燬Service中的Log輸出如下:

03-16 10:15:27.361 17920-17920/com.sample.app E/CustomBindService: ----- onCreate()  
03-16 10:15:27.361 17920-17920/com.sample.app E/CustomBindService: ----- onBind()  
03-16 10:15:30.211 17920-17920/com.sample.app E/CustomBindService: ----- onUnbind()  
03-16 10:15:30.211 17920-17920/com.sample.app E/CustomBindService: ----- onDestroy()  

總結

  • 兩種啓動方式都可在Intent中攜帶Bundle對象,向Service中傳遞一個Bundle對象。
  • 通過 startService() 啓動服務時,onBind()onUnbind() 這兩個生命週期是不會被回調的,通過 bindService() 綁定一個Service時,onStartCommand() 這個生命週期是不會被回調的。

Service的生命週期

Service的調用方式不一樣,所以調用的生命週期也是有區別的

Service生命週期調用順序

在Service的生命週期裏,常用的有:

4個手動調用的方法

方法 作用
startService() 啓動Service
stopService() 停止Service
bindService() 綁定Service
unbindService() 解綁Service

5個內部自動調用的方法

方法 作用
onCreate() 創建Service
onStartCommand() 啓動Service
onBind() 綁定Service
onUnbind() 解綁Service
onDestroy 銷燬Service
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章