Service

小鴻洋發表於2018-07-10

Service定義

  • Service是可以長時間執行在後臺的,不可見的,沒有介面的元件;
  • Service執行在主執行緒中;
  • Service可以跨程式呼叫。

為什麼使用Service

  • service可以放在獨立的程式中,更安全。
  • 使用service可以依賴現有的binder機制不需要在應用層面上處理執行緒同步的繁雜工作。系統可以重新啟動異常死去的service。
  • intentservice使用佇列的方式將請求的佇列加入到intent佇列中,然後開啟一個 thread 執行緒,對於非同步的startservice請求,intentservice會處理完第一個之後處理第二個,每一個請求都會在單獨的一個work thread 中處理。不會阻塞應用程式的主執行緒,這就給我們提供了一個思路,每一個耗時的操作都可以使用intentservice中執行

Service基本啟動方式:StartService;bindService

StartService特點

  • onCreate只會執行一次,只要呼叫startService,onStartCommand一定會執行
  • Service執行在main執行緒中,做耗時操作需要例外開子執行緒
  • 通過Intent進行傳參,在onStartCommand接收引數
  • 無法獲得Service物件,直接操作Service中的屬性和方法
  • 呼叫stopService後,Service會執行onDestory後停止

StartService優缺點

優點:使用簡單,和Activity一樣,只需要幾行程式碼即可啟動Service 
缺點:使用startService的方式,無法獲得Service物件,不能直接操作Service中的屬性和方法,只能通過Intent進行傳遞不同引數,重複呼叫startService,觸發onStartCommand。

StartService使用步驟

  1. 新建類繼承Service
  2. 重寫onCreate方法(在建立時呼叫的方法,可以用來做資料初始化,Service在沒有停止之前,只會執行一次)
  3. 實現onBind抽象方法
  4. 重寫onStartCommand(建立後會呼叫onStartCommand,此方法中可以接收呼叫者傳遞過來的引數,並且可以編寫需要的邏輯程式碼,當重複呼叫Service時,onStartCommand會重複執行)
  5. 重寫onDestroy方法 (在退出時呼叫,此方法中可以編寫釋放資源的操作)
  6. 在AndroidManifest檔案中註冊Service(使用標籤註冊)
  7. 使用startService方法啟動Service
  8. 使用stopService方法停止Service

StartService程式碼展示

xml檔案 
首先要在佈局檔案中設定兩個按鈕,用來啟動和停止Service

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.administrator.sharedapplication.Main3Activity">

    <Button
        android:id="@+id/start_btn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="啟動Service"/>
    <Button
        android:id="@+id/stop_btn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="停止Service"/>

</LinearLayout>

然後在Activity檔案中對按鈕進行定義、繫結ID、設定監聽和點選事件

package com.example.administrator.sharedapplication;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class Main3Activity extends AppCompatActivity implements View.OnClickListener{
    private Button startBtn;
    private Button stopBtn;
    private Intent intent;

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

        bindID();
    }

    private void bindID() {
        startBtn=findViewById(R.id.start_btn);
        stopBtn=findViewById(R.id.stop_btn);
        startBtn.setOnClickListener(this);
        stopBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.start_btn:
                intent = new Intent(this,MyService.class);
                startService(intent);//啟動service
                break;
            case R.id.stop_btn:
                stopService(intent);//停止service
                break;
                default:
                break;
        }
    }
}

最後在新建的類中寫入MyService方式啟動Service的步驟

package com.example.administrator.sharedapplication;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

public class MyService extends Service{

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

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("Service"+Thread.currentThread().getName(),"onCreate...");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("Service","onStartCommand...");

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    Log.e("Service"+Thread.currentThread().getName(),i+"***");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("Service"+Thread.currentThread().getName(),"onDestroy...");

    }
}

bindService特點

  1. onCreate,onBind只會執行一次
  2. Service執行在main執行緒中,做耗時操作需另開子執行緒
  3. 可以直接操作Service中的屬性和方法
  4. 呼叫unbindService後,Service會執行onUnbind,onDestroy方法後停止

bindService優缺點

優點:可以得到Service物件,靈活控制Service內部的屬性和方法。 
缺點:使用較為複雜

bindService使用步驟

  1. 新建類繼承Service
  2. 實現onBind方法 (這裡不同於startService中實現onBind方法那樣簡單。這裡需要在此方法中返回一個Binder子類物件。)
  3. 重寫onCreate方法
  4. 重寫onUnBind方法 (在呼叫unbindService方法解除繫結後,觸發此回撥函式)
  5. 重寫onDestroy方法
  6. 在AndroidManifest中註冊Service
  7. 實現ServiceConnection介面 (這裡是難點)
  8. 通過bindService繫結Service
  9. 通過unbindService解綁Service

bindService程式碼展示

在新建的類中寫入TestService 方式啟動Service的步驟

package com.example.administrator.serviceapplication;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by Administrator on 2018/3/23.
 */

public class TestService extends Service {

    private String TAG="TestService";

    private Guanjia guanjia = new Guanjia();

    class Guanjia extends Binder{
        //作用:得到當前Service物件
        public TestService getServiceObject(){
            return TestService.this;
        }
    }
    public void fly(){
        Log.e(TAG,"開飛機");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG,"onBind...");
        return guanjia;
    }

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

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG,"onCreate...");

    }

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

    }
}

IntentService特點

  • IntentService是繼承於Service並處理非同步任務的一個類
  • 在IntentService內有一個工作執行緒來處理非同步耗時操作
  • 此執行緒無需我們控制和維護
  • 當多次啟動時,會以佇列的形式,逐一執行
  • 當執行完耗時操作後,此Service會自動停止

IntentService優點

會建立獨立的worker執行緒來處理所有的Intent請求; 
會建立獨立的worker執行緒來處理onHandleIntent()方法實現的程式碼,無需處理多執行緒問題; 
所有請求處理完成後,IntentService會自動停止,無需呼叫stopSelf()方法停止Service; 
多次呼叫時,按佇列的順序逐一執行,每次執行都是從建立到銷燬的全部過程

IntentService和Service區別

  1. 首先IntentService是繼承自Service;
  2. Service不是一個單獨的程式,它和應用程式在同一個程式中;
  3. Service也不是一個執行緒,所以我們要避免在Service中進行耗時的操作;
  4. IntentService使用佇列的方式將請求的Intent加入佇列,然後開啟了一個Worker Thread(工作執行緒)在處理佇列中的Intent,對於非同步的startService請求, 
    IntentService會處理完成一個之後在處理第二個,每一個請求都會在一個單獨的Worker Thread中處理,不會阻塞應用程式的主執行緒。 
    因此,如果我們如果要在Service裡面處理一個耗時的操作,我們可以用IntentService來代替使用。
  5. 使用IntentService 必須首先繼承IntentService並實現onHandleIntent()方法,將耗時的任務放在這個方法執行,其他方面,IntentService和Service一樣。

IntentService使用步驟

  • 新建類繼承IntentService
  • 實現父類的構造方法
  • 重寫onHandleIntent()方法
  • 重寫onCreate方法
  • 重寫onDesttory方法
  • 在AndroidManifest檔案中註冊Service(容易忘記或出錯)
  • 在有Content的環境下啟動Service

IntentService程式碼展示

xml檔案 
首先要在佈局檔案中設定兩個按鈕,用來開啟和停止IntentService

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.administrator.serviceapplication.Main3Activity">

    <Button
        android:id="@+id/start_btn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="開啟IntentService"/>
    <Button
        android:id="@+id/stop_btn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="停止IntentService"/>
</LinearLayout>

然後在Activity檔案中對按鈕進行定義、繫結ID、設定監聽和點選事件

package com.example.administrator.serviceapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class Main3Activity extends AppCompatActivity implements View.OnClickListener{
    private Button startBtn;
    private Button stopBtn;

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

    private void bindID() {
        startBtn=findViewById(R.id.start_btn);
        stopBtn=findViewById(R.id.stop_btn);
        startBtn.setOnClickListener(this);
        stopBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.start_btn:
                break;
            case R.id.stop_btn:
                break;
        }
    }
}

最後在新建的類中寫入MyIntentService 方式啟動Service的步驟

package com.example.administrator.serviceapplication;

import android.app.IntentService;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by Administrator on 2018/3/23.
 */

public class MyIntentService extends IntentService {
    public MyIntentService(String name) {
        super(name);
    }
    public MyIntentService(){
        super("");

    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        for (int i=0;i<10;i++){
            try {
                Log.e("MyIntentService",i+"***");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

相關文章