服務總覽

Service應用程式元件,可以在背景執行長時間執行的作業。但並未提供使用者介面。啟動後,即使使用者切換至其他應用程式,服務仍可能繼續執行一段時間。此外,元件也可以繫結至服務以便與其互動,甚至執行處理序間通訊 (IPC)。舉例來說,服務可以在背景處理網路交易、播放音樂、執行檔案 I/O,或是與內容供應器互動。

注意:服務會在其代管程序的主要執行緒中執行;除非您另行指定,否則服務「不會」建立自己的執行緒,也不會在獨立程序中執行。您應在服務的另一個執行緒中執行所有封鎖作業,以免發生應用程式無回應 (ANR) 錯誤。

服務類型

以下是三種不同類型的服務:

前景

前景服務會執行使用者可察覺的部分作業。舉例來說,音訊應用程式會使用前景服務播放音軌。前景服務必須顯示通知。即使使用者未與應用程式互動,前景服務仍會繼續執行。

使用前景服務時,您必須顯示通知,讓使用者主動瞭解服務正在執行。除非服務已停止或從前景移除,否則無法關閉此通知。

進一步瞭解如何在應用程式中設定前景服務

注意: WorkManager API 提供靈活的排程工作方式,而且可視需要以前景服務的形式執行這些工作。在多數情況下,使用 WorkManager 比較適合直接使用前景服務。

背景
背景服務執行的作業,不會直接被使用者註意到。舉例來說,如果應用程式使用服務來壓縮其儲存空間,這通常是背景服務。

注意:如果應用程式指定的 API 級別為 26 以上,則應用程式本身不在前景時,系統會對執行背景服務設下限制。在大部分情況下,您不應從背景存取位置資訊。請改為使用 WorkManager 安排工作

已繫結
當應用程式元件透過呼叫 bindService() 繫結至服務時,就會「繫結」服務。繫結服務提供用戶端與伺服器介面,可讓元件與服務互動、傳送要求、接收結果,甚至可以在含有處理序間通訊 (IPC) 的程序間執行此操作。只有在其他應用程式元件繫結至繫結服務的情況下,繫結服務才會執行。多個元件可以一次繫結至服務,但如果所有元件都解除繫結,服務就會遭到刪除。

雖然本說明文件一般將討論啟動流程和繫結的服務,但您的服務能以兩種方式運作,因此您可以啟動 (無限期執行) 並允許繫結。您只需要實作多種回呼方法即可:onStartCommand()允許元件啟動,onBind()以及允許繫結。

無論服務是啟動、繫結,或兩者皆有,任何應用程式元件都能使用服務 (甚至是透過個別應用程式) 的方式,就像使用任何元件都能使用活動的方式一樣,方法是以 Intent 啟動服務。不過,您可以在資訊清單檔案中宣告服務為私人,並封鎖其他應用程式的存取權。請參閱「在資訊清單中宣告服務」一節,進一步討論。

選擇服務和執行緒

服務只是可在背景執行的元件,即使使用者並未與應用程式互動,也請您只在必要時才建立服務。

如果您必須在使用者與應用程式互動時,在主執行緒外執行工作,請改為在其他應用程式元件的情境中建立新的執行緒。舉例來說,如果您想播放某些音樂,但只在活動執行期間播放,您可以在 onCreate() 中建立執行緒,在 onStart() 中開始執行,並在 onStop() 中停止執行該執行緒。此外,也建議您使用 java.util.concurrent 套件或 Kotlin 協同程式中的執行緒集區和執行工具,而非傳統的 Thread 類別。如要進一步瞭解如何將執行作業移至背景執行緒,請參閱 Android 的執行緒作業文件。

請注意,如果您使用服務,服務預設仍會在應用程式的主執行緒中執行,因此,如果服務會執行密集或造成阻斷的作業,您還是應該在服務中建立新的執行緒。

基本概念

如要建立服務,您必須建立 Service 的子類別或使用其現有的子類別。在實作中,您必須覆寫某些回呼方法,處理服務生命週期的重要層面,並提供可讓元件視需要繫結至服務的機制。以下是您應該覆寫的最重要回呼方法:

onStartCommand()
當其他元件 (例如活動) 要求啟動服務時,系統會藉由呼叫 startService() 來叫用這個方法。執行這個方法時,服務會啟動,並可以無限期在背景執行。如果您實作此操作,請自行呼叫 stopSelf()stopService() 以在工作完成時停止服務。如果您只想提供繫結,則不需要實作這個方法。
onBind()
當另一個元件要與服務繫結 (例如執行 RPC) 時,系統會呼叫 bindService() 來叫用這個方法。實作此方法時,您必須提供一個介面,供用戶端透過傳回 IBinder 來與服務通訊。您必須一律實作此方法;但是,如果您不想允許繫結,則應傳回空值。
onCreate()
系統會在初次建立服務時叫用這個方法,藉此執行一次性設定程序 (在呼叫 onStartCommand()onBind() 之前)。如果服務已在執行,系統就不會呼叫此方法。
onDestroy()
如果服務已停止使用且即將遭到刪除,系統會叫用這個方法。您的服務應實作此方法來清除任何資源,例如執行緒、已註冊的事件監聽器或接收器。這是服務最後一次收到的呼叫。

如果元件透過呼叫 startService() 啟動服務 (進而呼叫 onStartCommand()),服務會繼續執行,直到 stopSelf() 或其他元件本身透過呼叫 stopService() 將其停止。

如果元件呼叫 bindService() 以建立服務,且「未」呼叫 onStartCommand(),只有在元件繫結時,服務才會執行。服務與所有用戶端解除繫結後,系統會刪除服務。

只有在記憶體不足時,Android 系統才會停止服務,而且必須復原有使用者焦點的活動的系統資源。如果服務繫結至具有使用者焦點的活動,就不太可能遭到終止;如果服務被宣告為「在前景執行」,則幾乎不會終止。如果服務啟動且長時間執行,系統就會隨時間降低在背景工作清單中的位置,而且服務容易遭到終止。如果服務已啟動,您就必須將服務設計為能夠妥善處理系統的重新啟動作業。如果系統終止服務,服務會在資源可供使用時立即重新啟動,但這也取決於從 onStartCommand() 傳回的值。如要進一步瞭解系統刪除服務的時機,請參閱「處理程序和執行緒」文件。

以下各節將說明如何建立 startService()bindService() 服務方法,以及如何從其他應用程式元件使用這些方法。

在資訊清單中宣告服務

您必須在應用程式的資訊清單檔案中宣告所有服務,就像設定活動和其他元件時一樣。

如要宣告服務,請將 <service> 元素新增為 <application> 元素的子項。範例如下:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

如要進一步瞭解如何在資訊清單中宣告服務,請參閱 <service> 元素參考資料。

您可以在 <service> 元素中加入其他屬性,藉此定義各項屬性,例如啟動服務所需的權限,以及執行服務的程序。android:name 屬性是唯一的必要屬性,它會指定服務的類別名稱。發布應用程式後,請保留這個名稱,以免程式碼因使用明確意圖啟動或繫結服務而遭到破壞的風險 (請參閱網誌文章「無法變更的事項」)。

注意:為確保應用程式安全無虞,請在啟動 Service 時一律使用明確意圖,且不要宣告服務的意圖篩選器。使用隱含意圖啟動服務會危害安全性,因為您無法確定哪個服務會回應意圖,而使用者也無法查看哪個服務會啟動。從 Android 5.0 (API 級別 21) 開始,如果您使用隱含意圖呼叫 bindService(),系統會擲回例外狀況。

您可以加入 android:exported 屬性並將其設為 false,確保只有您的應用程式可以使用服務。這樣即使其他應用程式使用了明確意圖,也能避免其他應用程式啟動您的服務。

注意:使用者可以查看裝置上執行哪些服務。如果他們發現不認得或信任的服務,可以停止該服務。為了避免使用者不小心停止服務,您必須在應用程式資訊清單的 <service> 元素中加入 android:description 屬性。在說明中,請提供簡短說明,說明服務的用途和優點。

正在建立已開始服務

已啟動的服務是指另一個元件藉由呼叫 startService() 來啟動,進而呼叫服務的 onStartCommand() 方法。

服務啟動後,其生命週期與啟動服務的元件無關。即使啟動服務的元件已刪除,服務也可以無限期在背景執行。因此,服務應在工作完成時自行停止 (透過呼叫 stopSelf()),或是其他元件透過呼叫 stopService() 來停止工作。

應用程式元件 (例如活動) 可透過呼叫 startService() 來啟動服務,並傳遞指定服務的 Intent,包括任何供服務使用的資料。服務會在 onStartCommand() 方法中收到這個 Intent

例如,假設某項活動需要將一些資料儲存至線上資料庫。活動可以啟動隨附服務,並將意圖傳遞至 startService(),以傳送要儲存的資料。服務會在 onStartCommand() 中收到意圖、連線到網際網路,並執行資料庫交易。交易完成後,服務會自行停止並刪除。

注意:服務會在與應用程式相同的程序中執行,且預設會在該應用程式的主執行緒中執行。當使用者與同一應用程式中的活動互動時,如果您的服務執行密集或封鎖作業,服務會減慢活動效能。為了避免影響應用程式效能,請在服務中啟動新的執行緒。

Service 類別是所有服務的基礎類別。擴充此類別時,請務必建立新的執行緒,讓服務可在其中完成所有工作;根據預設,服務會使用應用程式的主執行緒,因此可能會降低應用程式執行的任何活動效能。

Android 架構也提供 ServiceIntentService 子類別,使用工作站執行緒一次處理所有啟動要求。由於已引入背景執行限制,因此不建議使用這個類別用於新應用程式,因為自 Android 8 Oreo 開始,它無法正常運作。此外,自 Android 11 起也已淘汰。 您可以使用 JobIntentService 取代與新版 Android 相容的 IntentService

以下各節將說明如何實作自己的自訂服務,不過在大多數用途中,我們都建議您改用 WorkManager。請參閱 Android 背景處理指南,瞭解是否有符合您需求的解決方案。

擴充 Service 類別

您可以擴充 Service 類別來處理每個傳入的意圖。基本導入方式如下:

Kotlin

class HelloService : Service() {

    private var serviceLooper: Looper? = null
    private var serviceHandler: ServiceHandler? = null

    // Handler that receives messages from the thread
    private inner class ServiceHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            try {
                Thread.sleep(5000)
            } catch (e: InterruptedException) {
                // Restore interrupt status.
                Thread.currentThread().interrupt()
            }

            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(msg.arg1)
        }
    }

    override fun onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
            start()

            // Get the HandlerThread's Looper and use it for our Handler
            serviceLooper = looper
            serviceHandler = ServiceHandler(looper)
        }
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show()

        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        serviceHandler?.obtainMessage()?.also { msg ->
            msg.arg1 = startId
            serviceHandler?.sendMessage(msg)
        }

        // If we get killed, after returning from here, restart
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        // We don't provide binding, so return null
        return null
    }

    override fun onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
    }
}

Java

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

範例程式碼會處理 onStartCommand() 中的所有來電,並將工作發布至在背景執行緒上執行的 Handler。運作方式與 IntentService 類似,並依序處理所有要求。您可以變更程式碼,使其在執行緒集區中執行工作,例如在多個要求同時執行多項要求時。

請注意,onStartCommand() 方法必須傳回整數。整數是一個值,用來說明系統應如何在系統終止服務的情況下繼續服務。onStartCommand() 的傳回值必須是下列其中一個常數:

START_NOT_STICKY
如果系統在 onStartCommand() 傳回後終止服務,請「不要」重新建立服務,除非有待處理的意圖。這是最安全的做法,可避免在非必要時執行您的服務,以及應用程式只要重新啟動任何未完成的工作時。
START_STICKY
如果系統在 onStartCommand() 傳回後終止服務,請重新建立服務並呼叫 onStartCommand(),但「不要」重新傳送最後一個意圖。除非有可啟動服務的待處理意圖,否則系統會以空值意圖呼叫 onStartCommand()。在這種情況下,這些意圖就會傳送。這適用於未執行指令,但會無限期執行且正在等待工作的媒體播放器 (或類似的服務)。
START_REDELIVER_INTENT
如果系統在 onStartCommand() 傳回後終止服務,請重新建立服務,並使用最後一個傳送至服務的意圖呼叫 onStartCommand()。系統會依序傳送所有待處理意圖。這種做法適用於主動執行應立即恢復工作的服務,例如下載檔案。

如要進一步瞭解這些傳回值,請參閱每個常數的連結參考說明文件。

啟動服務

您可以透過將 Intent 傳遞至 startService()startForegroundService(),從活動或其他應用程式元件啟動服務。Android 系統會呼叫服務的 onStartCommand() 方法,並將該方法傳遞給指定啟動服務的 Intent

注意:如果應用程式指定的 API 級別為 26 以上,系統會對使用或建立背景服務設下限制,除非應用程式本身位於前景。如果應用程式需要建立前景服務,則應用程式應呼叫 startForegroundService()。該方法會建立背景服務,但該方法可向系統表明服務會將本身提升至前景。服務建立後,服務必須在五秒鐘內呼叫其 startForeground() 方法。

舉例來說,活動可以使用 startService() 的明確意圖,啟動上一節 (HelloService) 中的範例服務,如下所示:

Kotlin

startService(Intent(this, HelloService::class.java))

Java

startService(new Intent(this, HelloService.class));

startService() 方法會立即傳回,Android 系統會呼叫服務的 onStartCommand() 方法。如果服務尚未執行,系統會先呼叫 onCreate(),然後再呼叫 onStartCommand()

如果服務未提供繫結,則透過 startService() 傳送的意圖,是應用程式元件與服務之間唯一的通訊模式。不過,如果您希望服務傳回結果,啟動服務的用戶端可以為廣播建立 PendingIntent (使用 getBroadcast()),並將其傳送至啟動服務的 Intent 中的服務。然後,服務就可以使用廣播來傳送結果。

多項啟動服務的要求會導致系統對服務的 onStartCommand() 發出多次對應的呼叫。不過,如要停止服務,只需要提出一次要求 (使用 stopSelf()stopService())。

停止服務

已啟用的服務必須管理本身的生命週期。也就是說,除非必須復原系統記憶體,且服務會在 onStartCommand() 傳回後繼續執行,否則不會停止或刪除服務。服務必須藉由呼叫 stopSelf() 自行停止,或者其他元件可以透過呼叫 stopService() 將其停止。

透過 stopSelf()stopService() 要求停止服務後,系統會盡快刪除服務。

如果您的服務同時處理對 onStartCommand() 的多項要求,請勿在處理啟動要求後停止服務,因為您可能已收到新的開始要求,而在第一個要求結束時停止要求,第二個要求就會終止。如要避免這個問題,您可以使用 stopSelf(int),確保停止服務的要求一律都是根據最近的啟動要求。也就是說,當您呼叫 stopSelf(int) 時,您會將啟動要求的 ID (傳送到 onStartCommand()startId) 傳遞給停止要求對應的 ID。然後,如果服務在您能夠呼叫 stopSelf(int) 之前收到新的啟動要求,則 ID 不相符,服務也不會停止。

注意:為了避免浪費系統資源並消耗電池電力,請務必在作業完成後停止應用程式服務。如有必要,其他元件可以透過呼叫 stopService() 來停止服務。即使您已為服務啟用繫結,如果服務收到對 onStartCommand() 的呼叫,您仍須自行停止服務。

如要進一步瞭解服務的生命週期,請參閱下方的管理服務生命週期一節。

正在建立繫結服務

繫結服務可透過呼叫 bindService() 建立長期連線,讓應用程式元件繫結至該服務。通常不允許元件呼叫 startService() 將其「啟動」

當您想透過應用程式中的活動和其他元件與服務互動,或透過處理序間通訊 (IPC) 向其他應用程式公開應用程式的某些功能時,請建立繫結服務。

如要建立繫結服務,請實作 onBind() 回呼方法以傳回 IBinder,以定義與服務通訊的介面。接著,其他應用程式元件可以呼叫 bindService() 來擷取介面,並開始呼叫服務的方法。服務只會運作以提供繫結的應用程式元件,因此如果沒有繫結至該服務的應用程式元件,系統就會將其刪除。您「不必」按照透過 onStartCommand() 啟動服務時所需的方式停止繫結服務。

如要建立繫結服務,您必須定義介面,指定用戶端如何與服務進行通訊。服務和用戶端之間的介面必須是 IBinder 的實作,且您的服務必須透過 onBind() 回呼方法傳回的內容。用戶端收到 IBinder 後,即可開始透過該介面與服務互動。

多個用戶端可以同時繫結至服務。用戶端與服務互動完畢後,就會呼叫 unbindService() 以解除繫結。當沒有任何用戶端繫結至服務時,系統會銷毀服務。

實作繫結服務的方法有很多種,實作方式比已開始的服務更加複雜。基於上述原因,繫結服務討論會顯示在繫結服務的另一份文件中。

傳送通知給使用者

服務執行時,可以透過 Snackbar 通知狀態列通知通知事件給使用者。

Snackbar 通知是一種訊息,只會在目前視窗的表面上顯示,直到消失前。狀態列通知在狀態列中提供內含訊息的圖示,使用者選取該訊息即可採取行動 (例如啟動活動)。

一般來說,當背景工作 (例如檔案下載完成),且使用者現在可以對其執行動作時,狀態列通知通常是最好的技巧。當使用者在展開的檢視畫面中選取通知時,通知可能會啟動活動 (例如顯示下載的檔案)。

管理服務的生命週期

服務的生命週期比活動的生命週期要簡單許多。但更需要特別留意服務的建立和刪除方式,因為服務可以在使用者不知情的情況下在背景中執行。

服務生命週期 (從建立到刪除時) 可採用下列兩種路徑之一:

  • 已啟動的服務

    其他元件呼叫 startService() 時,系統會建立服務。接著,服務會無限期執行,且必須呼叫 stopSelf() 自行停止。另一個元件也可以呼叫 stopService() 來停止服務。服務停止後,系統會刪除服務。

  • 繫結服務

    當其他元件 (用戶端) 呼叫 bindService() 時,就會建立服務。接著,用戶端會透過 IBinder 介面與服務通訊。用戶端可以呼叫 unbindService() 來關閉連線。多個用戶端可以繫結至同一服務,所有用戶端都解除繫結後,系統會刪除該服務。服務「不」需要停止本身。

這兩個路徑並非完全獨立的路徑,您可以繫結至已使用 startService() 啟動的服務。舉例來說,您可以透過用來識別要播放音樂的 Intent 呼叫 startService(),啟動背景音樂服務。之後,當使用者想對播放器進行部分控制,或取得目前歌曲的相關資訊時,活動可以透過呼叫 bindService() 繫結至服務。在這類情況下,除非所有用戶端都解除繫結,否則 stopService()stopSelf() 實際上不會停止服務。

實作生命週期回呼

如同活動,服務具有生命週期回呼方法,您可以導入此方法,監控服務狀態的變化,並在適當時間執行工作。以下架構服務示範每個生命週期方法:

Kotlin

class ExampleService : Service() {
    private var startMode: Int = 0             // indicates how to behave if the service is killed
    private var binder: IBinder? = null        // interface for clients that bind
    private var allowRebind: Boolean = false   // indicates whether onRebind should be used

    override fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Java

public class ExampleService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

注意:有別於活動生命週期回呼方法,您「不需要」呼叫這些回呼方法的父類別實作。

圖 2. 服務生命週期。左圖顯示使用 startService() 建立服務時的生命週期,右圖顯示使用 bindService() 建立服務時的生命週期。

圖 2 說明服務的典型回呼方法。雖然圖表會將 startService() 建立的服務與 bindService() 建立的服務分開,但請注意,無論服務如何啟動,用戶端都可能允許用戶端繫結至該服務。最初使用 onStartCommand() 的服務 (由用戶端呼叫 startService()) 仍可收到對 onBind() 的呼叫 (用戶端呼叫 bindService() 時)。

實作這些方法後,您可以監控服務生命週期的兩個巢狀迴圈:

注意:雖然已啟動的服務因呼叫 stopSelf()stopService() 而停止,但服務不會有各自的回呼 (即沒有 onStop() 回呼)。除非服務繫結至用戶端,否則系統會在服務停止時刪除服務,onDestroy() 是唯一收到的回呼。

如要進一步瞭解如何建立提供繫結的服務,請參閱「繫結服務」文件,如要進一步瞭解 onRebind() 回呼方法,請參閱「管理繫結服務的生命週期」一節。