Android四大組件之Service,以及IntentService

@[toc]php

Service基本介紹

Android四大組件之一,沒有界面的後臺服務。咱們若是想要在後臺執行一些任務,會用到Service。好比:後臺下載更新;後臺播放音樂等等。java

Service生命週期

  • Service有兩種啓動方式,經過兩種不一樣的啓動方式,生命週期執行方法也是不同的:android

    1. startService:onCreate --> onStartCommand --> onStart ---> onDestroyapp

      相對應的中止方法爲:stopService異步

    重複調用 startService 不會從新走 onCreate方法,只會走 onStartCommand --> onStartide

    1. bindService: onCreate --> onBind ---> onUnBind ---> onDestroyoop

      相對應的解綁方法爲: unBindService源碼分析

    重複調用 bindService 方法,不會再次走 onCreate 方法,只會走 onBind 方法佈局

  • 混合啓動:ui

    service的onCreate只會走一次。

    先調用 startService,再調用 bindService。 onCreate --> onStartCommand --> onStart --(此時調用 bindService )---> onBind。

    先調用 bindService,再調用 startService。 onCreate --> onBind --(此時調用 startService )---> onStartCommand --> onStart。

    混合啓動想要銷燬 Service 必須 stopService、unBindService 都調用,不然無效。

Service的基本用法

  • 首先建立一個class繼承Service

    繼承 service 的服務,在裏面不能進行耗時操做,由於它自己也是依賴於主進程的,不是一個單獨的線程,沒法進行耗時操做。

public class MyService extends Service {
    public static final String TAG = "MyService";

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

    @Override
    public void onStart(Intent intent, int startId) {
        Log.i(TAG, "onStart: ");
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        //在這裏建立一個子線程,睡眠5秒鐘後,調用關閉 service 方法
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    stopService1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        // 返回代理對象
        return new MyBinder();
    }

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

    public void stopService1() {
        Log.i(TAG, "中止服務");
        stopSelf();
    }
    
    public void receiveMsg(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy: ");
        super.onDestroy();
    }
    
    //建立一個Service的代理類,經過它能夠調用Service中的方法。
    public class MyBinder extends Binder {

        public void sendMsg(String msg) {
            receiveMsg(msg);
        }
    }
}

複製代碼
  • 在 AndroidManifest.xml 文件中註冊:
<!-- enabled 是否能夠被激活,若是設置爲false,就沒法激活Service-->
<!-- exported 是否能夠被外部*進程*激活,-->
<service android:name=".service.MyService" android:enabled="true" android:exported="false" />
複製代碼
  • 在Activity中啓動,以及關閉,以及怎麼調用Service中的方法:
public class ServiceActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mBtnStartService;
    private Button mBtnStopService;
    private Button mBtnBindService;
    private Button mBtnUnbindService;
    private MyService.MyBinder myIBinder;
    private MyConnection myConnection;
    private Button mBtnCallService;//調用Service中的方法

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

    private void initView() {
        mBtnStartService = findViewById(R.id.btn_start_service);
        mBtnStopService = findViewById(R.id.btn_stop_service);
        mBtnBindService = findViewById(R.id.btn_bind_service);
        mBtnUnbindService = findViewById(R.id.btn_unbind_service);
        mBtnCallService = findViewById(R.id.btn_call_service);
    }

    private void initAction() {
        mBtnStartService.setOnClickListener(this);
        mBtnStopService.setOnClickListener(this);
        mBtnBindService.setOnClickListener(this);
        mBtnUnbindService.setOnClickListener(this);
        mBtnCallService.setOnClickListener(this);
    }

    private void initData() {
        myConnection = new MyConnection();
    }

    @Override
    public void onClick(View v) {
        Intent service = new Intent(this, MyService.class);
        switch (v.getId()) {
            case R.id.btn_start_service:
                startService(service);
                break;
            case R.id.btn_stop_service:
                stopService(service);
                break;
            case R.id.btn_bind_service:
                bindService(service, myConnection, BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbind_service:
                unbindService(myConnection);
                break;
            case R.id.btn_call_service:
                myIBinder.sendMsg("我是Activity傳來的消息");
                break;
            default:
                break;
        }
    }

    public class MyConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        //獲取Service的代理
            myIBinder = (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

複製代碼
  • xml佈局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".service.ServiceActivity">

    <Button android:id="@+id/btn_start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start_service" />

    <Button android:id="@+id/btn_stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop_service" />

    <Button android:id="@+id/btn_bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bind_service" />

    <Button android:id="@+id/btn_unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="unbind_service" />

    <Button android:id="@+id/btn_call_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="調用Service內部方法" />

</LinearLayout>
複製代碼
  • 實驗結果:

    點擊 bindService 綁定Service,而後點擊 btn_call_service ,彈出吐司 「我是Activity傳來的消息」,完成Activity和Service的調用

  • 注意: Service是有可能綁定失敗的,具體緣由和解決方案:bindService不調用onServiceConnected的問題

  • onStartCommand:

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

    onStartComand使用時,返回的是一個(int)整形。

    這個整形能夠有四個返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。

    它們的含義分別是:

    1. START_STICKY:若是service進程被kill掉,保留service的狀態爲開始狀態,但不保留遞送的intent對象。隨後系統會嘗試從新建立service,因爲服務狀態爲開始狀態,因此建立服務後必定會調用onStartCommand(Intent,int,int)方法。若是在此期間沒有任何啓動命令被傳遞到service,那麼參數Intent將爲null。

    2. START_NOT_STICKY:「非粘性的」。使用這個返回值時,若是在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啓該服務

    3. START_REDELIVER_INTENT:重傳Intent。使用這個返回值時,若是在執行完onStartCommand後,服務被異常kill掉,系統會自動重啓該服務,並將Intent的值傳入。

    4. START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill後必定能重啓。

    flags表示啓動服務的方式:

    Additional data about this start request. Currently either 0,START_FLAG_REDELIVERY,or START_FLAG_RETRY。

    1. START_FLAG_REDELIVERY:若是你實現onStartCommand()來安排異步工做或者在另外一個線程中工做, 那麼你可能須要使用START_FLAG_REDELIVERY來讓系統從新發送一個intent。這樣若是你的服務在處理它的時候被Kill掉, Intent不會丟失.

    2. START_FLAG_RETRY:表示服務以前被設爲START_STICKY,則會被傳入這個標記。

IntentService:

  • 介紹

    相對於Service而言,IntentService自己擁有一個子線程,能夠進行耗時操做,在任務代碼完成後,會自動銷燬服務,不用手動調用。

  • 代碼:

public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");
    }
多出一個onHandleIntent方法,能夠在裏面作耗時操做
    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(5000);
            Log.i(TAG, "onHandleIntent: 睡了5秒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


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

複製代碼
  • 步驟:和Service同樣,在 Activity 中調用 startService 方法開啓服務。只不過 IntentService 在開啓後,onHandleIntent 中的代碼執行完後,會自動銷燬服務。

  • 實驗結果:

    2019-03-05 00:26:14.972 16106-16106/com.sjc.myapplication I/MyIntentService: onCreate: 
    2019-03-05 00:26:14.981 16106-16106/com.sjc.myapplication I/MyIntentService: onStart: 
    2019-03-05 00:26:19.983 16106-17272/com.sjc.myapplication I/MyIntentService: onHandleIntent: 睡了52019-03-05 00:26:19.985 16106-16106/com.sjc.myapplication I/MyIntentService: onDestroy: 
    
    複製代碼
  • 源碼分析: IntentService源碼並不長。

//自己是一個抽象類,繼承與Service
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;
    //在內部建立了一個 Handler對象
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //執行完 onHandleIntent 方法後,調用了stopSelf方法,銷燬服務。
            onHandleIntent((Intent)msg.obj);
            //銷燬服務
            stopSelf(msg.arg1);
        }
    }

   
    public IntentService(String name) {
        super();
        mName = name;
    }

   
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
      
        super.onCreate();
        //在onCreate 中建立了一個 HandlerThread 線程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        //開啓線程
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
    //onStrat 中發送消息,而後回調ServiceHandler 的 handleMessage 方法
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

 
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
    //退出Looper
        mServiceLooper.quit();
    }

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

    //抽象方法,在子類中重寫。
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

複製代碼
  • 總結: IntentService 只能經過 startService 方式開始有用,纔會回調 onHandleIntent 方法。且執行完子線程中的任務後,自動銷燬。若是使用 bindService 方式開啓,和普通 Service 沒有差異。

參考文章:

相關文章
相關標籤/搜索