多執行緒和回呼入門
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
「以 Kotlin 開發 Android 應用程式」課程假設您已熟悉多執行緒的概念和術語。這個頁面屬於概略介紹和複習性質。
行動裝置都有處理器,而現今的裝置多半都有多個硬體處理器,各處理器會同時執行處理程序。這就是所謂的「多重處理程序」。
為了更有效率地使用處理器,作業系統可讓應用程式在處理程序內建立多個執行緒。這就是「多執行緒」功能。

這就像是同時閱讀多本書籍、每讀一章就換另一本,最終可以讀完所有書籍,但是同一時間點只能閱讀一本書。
要管理所有執行緒,需要略為動用基礎架構。

「排程器」會將優先順序等因素納入考量,確保所有執行緒都能順利完成執行。任何一本書都不該永遠在書架上積灰塵,但是如果書籍篇幅很長或者可以稍後再讀,可能要一段時間後才會送到您手中。
「調度工具」會設定執行緒,負責傳送您需要閱讀的書籍,並指定相關作業的結構定義。您可以將結構定義視為獨立的特殊閱讀室。某些結構定義最適合使用者介面作業,有些則專門用於處理輸入/輸出作業。
唯一需要另外注意的是,使用者導向的應用程式通常會具備在前景執行的「主執行緒」,並且會調度可在背景執行的其他執行緒。
在 Android 中,主執行緒是處理所有 UI 更新的單一執行緒,又稱為「UI 執行緒」,這個執行緒同時也會呼叫所有點擊處理常式,以及其他 UI 和生命週期回呼。UI 執行緒是預設執行緒。除非應用程式明確切換執行緒,或是使用在其他執行緒上執行的類別,否則應用程式只會在主執行緒上進行各項工作。
這可能是個挑戰。UI 執行緒必須順暢執行,才能確保提供優質的使用者體驗。為了避免使用者在應用程式中遇到任何卡頓情形,主執行緒每 16 毫秒或更短的間隔 (大約每秒 60 影格數) 就必須更新畫面一次。就這個速度來看,人類眼中的影格變動過程完全可說是行雲流水。但要達到此效果,需於短時間內處理大量影格。因此在 Android 上,如何避免 UI 執行緒遭到封鎖,就顯得相當重要。「封鎖」在此情境下是指,UI 執行緒在等待其他事項 (例如等待資料庫完成更新) 期間,完全未執行任何動作。

許多常見工作耗時超過 16 毫秒,例如從網際網路擷取資料、讀取大型檔案,或是將資料寫入資料庫。因此,如果呼叫程式碼來執行主執行緒中的工作,可能會導致應用程式暫停、延遲,乃至凍結。但是,如果封鎖主執行緒的時間過長,應用程式甚至可能會當機,並顯示「應用程式無回應」(ANR) 對話方塊。
回呼
您可以透過幾種不同的方式處理主執行緒上的工作。
在不封鎖主執行緒的情況下,有種執行長時間工作的模式稱做「回呼」。利用回呼,您可以開始在背景執行緒上長時間執行工作。工作完成後,系統會呼叫做為引數的回呼,然後將結果告知主執行緒上的程式碼。
回呼算是不錯的模式,但有些缺點。大量使用回呼的程式碼會變得不易讀取且難以推論,因為程式碼雖然看起來是依序執行,但回呼程式碼日後會在某些非同步的時間點執行。此外,回呼也不允許使用例外狀況等部分語言功能。
協同程式
在 Kotlin 中,「協同程式」是能夠流暢有效處理長時間執行工作的解決方案。運用 Kotlin 協同程式,您可將以回呼為基礎的程式碼轉換為循序程式碼。依序編寫的程式碼通常較容易閱讀,甚至能使用例外狀況等語言功能。說到底,協同程式和回呼所做的工作其實並無二致,亦即等到長時間執行的工作產生結果,再繼續執行。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-08-18 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-08-18 (世界標準時間)。"],[],[],null,["# Multi-threading & callbacks primer\n\nThe\n[Developing Android Apps in Kotlin course](https://codelabs.developers.google.com/codelabs/kotlin-android-training-welcome/index.html?index=..%2F..index#0)\nassumes that you are familiar with the concept and terminology of\nmulti-threading. This page is a high-level introduction and refresher.\n\nMobile devices have processors, and these days, most devices have multiple\nhardware processors that each run processes concurrently. This is called\n*multiprocessing*.\n\nTo use processors more efficiently, the operating system can enable an\napplication to create more than one thread of execution within a process. This\nis called *multi-threading*.\n\nYou can think of it as reading multiple books at the same time, switching\nbetween books after each chapter, eventually finishing all books, but you can't\nread more than one book at the exact same time.\n\nIt takes a bit of infrastructure to manage all those threads.\n\nThe *scheduler* takes into account things such as priorities, and makes sure all\nthe threads get to run and finish. No book is allowed to sit in the shelf\nforever and gather dust, but if a book is very long, or can wait, it may take a\nwhile before it gets sent your way.\n\nThe *Dispatcher* sets up threads, that is, it sends you books that you need to\nread, and specifies a **context** for that to happen in. You can think of the\ncontext as a separate, specialized reading room. Some contexts are best for user\ninterface operations, and some are specialized to deal with input/output\noperations.\n\nThe only other thing to know is that a user-facing application usually has a\n*main thread* that runs in the foreground and can dispatch other threads that\nmay run in the background.\n\nOn Android, the main thread is a single thread that handles all updates to the\nUI. This main thread, also called the *UI thread*, is also the thread that calls\nall click handlers and other UI and lifecycle callbacks. The UI thread is the\ndefault thread. Unless your app explicitly switch threads or uses a class that\nruns on a different thread, everything your app does is on the main thread.\n\nThis creates a potential challenge. The UI thread has to run smoothly to\nguarantee a great user experience. For your app to display to the user without\nany visible pauses, the main thread has to update the screen every 16 ms or more\noften, or at about 60 frames per second. At this speed, humans perceive the\nchange of frames as completely smooth. That's a lot of frames and little time.\nTherefore, on Android it's essential to avoid blocking the UI thread. *Blocking*\nin this context means the UI thread is not doing anything at all while it waits\nfor something like a database to finish updating.\n\nMany common tasks take longer than 16 milliseconds, such as fetching data from\nthe internet, reading a large file, or writing data to a database. Therefore,\ncalling code to perform tasks like those from the main thread can cause the app\nto pause, stutter, or even freeze. And if you block the main thread for too\nlong, the app may even crash and present an \"application not responding\" (ANR)\ndialog.\n\nCallbacks\n---------\n\nYou have several options for how to get work done off of from the main thread.\n\nOne pattern for performing long-running tasks without blocking the main thread\nis *[callbacks](https://en.wikipedia.org/wiki/Callback_(computer_programming))*.\nBy using callbacks, you can start long-running tasks on a background thread.\nWhen the task completes, the callback, supplied as an argument, is called to\ninform your code of the result on the main thread.\n\nCallbacks are a great pattern, but they have a few drawbacks. Code that heavily\nuses callbacks can become hard to read and harder to reason about. Because while\nthe code looks sequential, the callback code will run at some asynchronous time\nin the future. In addition, callbacks don't allow the use of some language\nfeatures, such as exceptions.\n\nCoroutines\n----------\n\nIn Kotlin,\n*[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)*\nare the solution for handling long-running tasks elegantly and efficiently.\nKotlin coroutines let you convert callback-based code to sequential code. Code\nwritten sequentially is typically easier to read, and can even use language\nfeatures such as exceptions. In the end, coroutines and callbacks do exactly the\nsame thing: wait until a result is available from a long-running task and\ncontinue execution."]]