Android Service(上)


一 Service簡介

Service是Context的子類

Service是四大組件之一 用來在后台處理一些比較耗時的操作或者去執行某些需要長期運行的任務

 

二 注意

Service里面不能直接執行耗時的操作 因為Service里面所有方法執行都是在主線程

如果要執行耗時的操作 開啟子線程

 

三 Service特點

1. 沒有界面

2. 在后台長時間的運行

3. 無法自己啟動

4. 單例模式

 

四 新建一個Service

1. 繼承Service

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("HUANG", "onCreate");
    }

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

    @Nullable @Override
    public IBinder onBind(Intent intent) {
        Log.i("HUANG", "onBind");
        return null;
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("HUANG", "onDestroy");
    }

}

2. AndroidManifest.xml application節點里面配置service name屬性必須配置 其余可選

<service android:name=".service.MyService" />

3. 啟動Service startService()或者bindService()

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ServiceConnection mConnection; //服務的連接對象

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

        findViewById(R.id.start).setOnClickListener(this);
        findViewById(R.id.stop).setOnClickListener(this);
        findViewById(R.id.bind).setOnClickListener(this);
        findViewById(R.id.unbind).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.start:
                startService(new Intent(this, MyService.class));
                break;

            case R.id.stop:
                stopService(new Intent(this, MyService.class));
                break;

            case R.id.bind:
                Intent service = new Intent(this, MyService.class);
                mConnection = new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {}

                    @Override
                    public void onServiceDisconnected(ComponentName name) {}
                };
                bindService(service, mConnection, Context.BIND_AUTO_CREATE);
                break;

            case R.id.unbind:
                unbindService(mConnection);
                break;
        }
    }

}

 

五 Service生命周期

Service生命周期會因為啟動方式不一樣而不同 停止Service的方式也不同

當采用startService()方法啟動 與之有關的生命周期方法

onCreate() -> onStartCommand() -> onDestroy()

onCreate() 該方法在Service被創建時調用 只會被調用一次 無論調用多少次startService()方法和bindService()方法 Service也只被創建一次

onStartCommand() 只有采用startService()方法啟動時才會回調該方法 該方法在Service開始運行時被調用 多次調用startService()方法盡管不會多次創建Service 但onStartCommand()方法會被多次調用

onDestroy() 該方法在Service被銷毀時調用

只要調用一次stopService()方法便可以停止Service 無論之前它被調用了多少次的啟動Service方法

當采用bindService()方法啟動 與之有關的生命周期方法

onCreate() -> onBind() -> onUnbind() -> onDestroy()

onCreate() 該方法在Service被創建時調用 只會被調用一次 無論調用多少次startService()方法和bindService()方法 Service也只被創建一次

onBind() 只有采用bindService()方法啟動時才會回調該方法 該方法在調用者與Service綁定時被調用 當調用者與Service已經綁定 多次調用bindService()方法並不會導致該方法被多次調用

onUnbind() 只有采用bindService()方法啟動時才會回調該方法 該方法在調用者與Service解除綁定時被調用

onDestroy() 該方法在Service被銷毀時調用

只要調用一次unbindService()方法便可以停止Service 多次調用會報錯

如果一個Activity已經bindService() 那么Activity退出一定要unbindService() 否則報錯

多個客戶端可以綁定同一個Service 如果Service還未被啟動 bindService()方法可以啟動Service

如果先采用startService()方法啟動 接着又采用bindService()方法啟動(此處startService()和bindService()沒有先后順序)

這個時候單獨執行 stopService()或者unbindService() Service都不會被銷毀

只有先執行stopService() 接着又執行unbindService() Service才會被銷毀(此處stopService()和unbindService()沒有先后順序)

也就是說 一個Service必須要在兩種啟動方式都停止的情況下才會被銷毀

 

六 startService()和bindService()區別

1. 導致Service的生命周期不同

2. 停止Service的方式不同

3. startService()啟動的Service 在系統正在運行的服務中可以找到  bindService()啟動的Service 在系統正在運行的服務中找不到

4. startService()調用者和Service是沒有關系的 即使調用者退出了 Service仍然運行  bindService()調用者和Service是綁定在一起的 調用者一旦退出 Service也就終止 "同生共死"

 

七 startService()和bindService()應用場景

通過startService()和stopService()啟動關閉Service 適用於調用者和Service之間沒有交互的情況

通過bindService()和unbindService()啟動關閉Service 適用於調用者和Service之間需要方法調用或者傳遞參數

 

八 線程 進程 服務

線程: 是CPU執行的一個最小單元

進程: 是系統里面的一個最小單元 一個應用可以理解為一個進程 用戶啟動一個應用程序 操作系統就會為其分配一塊內存空間 CPU去啟動進程里面的主線程

服務: 服務不是線程 服務也不是進程 服務運行在進程里面(https://developer.android.com/reference/android/app/Service#WhatIsAService)

 

九 進程的優先級別

Android系統試圖盡可能長的保持一個應用程序進程 只有內存不足的時候 系統才會殺死進程

殺死進程是根據進程的優先級別 先殺級別低的 

進程的優先級別排序 前台進程 > 可視進程 > 服務進程 > 后台進程 > 空進程

1. 前台進程(用戶當前工作所需要的 一個進程如果滿足下列任何條件被認為是前台進程)

  1.1 運行着一個正在與用戶交互的Activity(onResume()方法已經被調用)

  1.2 寄宿着一個Service 該Service綁定到了一個與用戶交互的Activity

  1.3 有一個Service對象正在執行生命周期方法

  1.4 有一個BroadcastReceiver對象正在執行生命周期方法

2. 可視進程(沒有任何前台組件 但是仍然能影響用戶在屏幕上看到東西 一個進程如果滿足下列任何條件被認為是可視進程)

  2.1 寄宿着一個不是前台的Activity 但是它對用戶仍可見(onPause()方法已經被調用)

  2.2 寄宿着一個Service 該Service綁定到了一個可視的Activity

3. 服務進程(在后台 應用里面有一個用startService()方法啟動的服務在運行)

4. 后台進程(在后台 任務棧里面有Activity)

5. 空進程(在后台 任務棧里面沒有Activity)

前台進程和可視進程難以被殺 服務進程要保活 后台進程和空進程被殺了影響不大

把服務進程提升為前台進程

public class MyService extends Service {

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

        /**
         * Intent未指定Activity 無跳轉
         *
         * Intent已指定Activity
         *      應用在后台 跳轉到指定Activity 當指定Activity退出時 不管點擊通知前是在哪個頁面 都會回到本應用棧頂頁面
         *      應用不在后台 跳轉到指定Activity 當指定Activity退出時 回到點擊通知前的那個頁面
         *      注意: 指定Activity也受啟動模式限制
         * */
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                99, //requestCode
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT); //更新 同一個id並且同一個requestCode的PendingIntent

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setSmallIcon(R.mipmap.ic_launcher) //狀態欄顯示的小圖標
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) //下拉顯示的大圖標
                .setTicker("滴滴") //首次出現在通知欄 帶上升動畫效果
                .setContentTitle("ContentTitle") //標題
                .setContentText("ContentText") //內容
                .setWhen(System.currentTimeMillis()) //通知產生的時間 會在通知信息里顯示
                .setContentInfo("ContentInfo") //顯示信息
                .setPriority(NotificationCompat.FLAG_FOREGROUND_SERVICE) //設置通知優先級
                .setDefaults(Notification.DEFAULT_ALL) //設置通知默認的聲音 震動 呼吸燈
                .setAutoCancel(false) //點擊和清理可以去掉通知
                .setOngoing(true) //設置為一個正在進行的通知 通常是用來表示一個后台任務(如播放音樂 文件下載)
                .setContentIntent(pendingIntent);

        // 把服務進程提升為前台進程
        startForeground(100, builder.build());
    }

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

}

如果要保證一個應用在后台不被殺死 可以先在應用里面采用startService()方法啟動一個服務 再把服務進程提升為前台進程

 

Android Service(下)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM