iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0

剩下最後五天了加油!!

今天來介紹Thread,ok開始!

Thread不是Meta的嗎( º﹃º )?

所有的UI操作,例如繪製畫面、回應按鈕點擊等,都在一個被稱為主執行緒(Main Thread)或UI執行緒(UI Thread)的單一執行緒上執行。如果在這個主執行緒上執行耗時的操作,如下載檔案、存取資料庫、複雜運算,就會導致 UI 被阻塞,畫面凍結,最終可能跳出應用程式無回應之類的錯誤

為了解決問題,我們使用Thread將這些耗時任務移到背景執行緒 (Background Thread) 中執行,讓主執行緒保持流暢,專心處理 UI 互動。

用Thread的兩個規則

  • 不要阻塞UI執行緒:將所有耗時操作(網路請求、檔案讀寫、資料庫操作……)都放到背景執行緒中
  • 不要從背景執行緒直接存取UI元件:不要在背景執行緒中直接更新TextView、ImageView等 UI 元件

背景執行緒完成任務,要安全的將結果更新回UI介面上,可以透過HandlerrunOnUiThread()等機制溝通

範例

建立並啟動背景執行緒

Activity 中,可以透過 new Thread().start() 來啟動一個新的執行緒

從背景執行緒安全更新 UI

背景執行緒完成任務後,要將更新UI的程式碼傳遞回主執行緒來執行

  • runOnUiThread(): 可以將一個Runnable物件post到UI執行緒的事件佇列裡
  • Handler: 在主執行緒中建立一個 Handler,它會自動與主執行緒的訊息迴圈綁定。任何執行緒都可以透過這個Handler 將訊息或 Runnable 物件傳遞回主執行緒執行

activity_main.xml

這邊用點擊按鈕後,啟動一個背景執行緒模擬3秒的耗時工作,然後用 Handler 將結果更新回TextView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:id="@+id/start_main_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開始耗時任務" />

    <TextView
        android:id="@+id/status_main_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="等待任務開始..."/>

</LinearLayout>

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView statusTextView;
    private Button startButton;

    //建立主執行緒Handler
    private Handler mainHandler = new Handler(Looper.getMainLooper());

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

        statusTextView = findViewById(R.id.status_main_tv);
        startButton = findViewById(R.id.start_main_btn);

        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startBackgroundTask();
            }
        });
    }

    private void startBackgroundTask() {
        //禁用按鈕,讓執行時不能重複點擊
        startButton.setEnabled(false);
        statusTextView.setText("任務執行中...");

        //建立並啟動背景執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //模擬耗時
                    Thread.sleep(3000);

                    //使用Handler將UI更新post回主執行緒
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            //更新UI並重新啟用按鈕
                            statusTextView.setText("任務完成!");
                            startButton.setEnabled(true);
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();

                    //發生異常時恢復按鈕狀態
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            statusTextView.setText("任務執行失敗");
                            startButton.setEnabled(true);
                        }
                    });
                }
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //移除所有pending的callbacks
        mainHandler.removeCallbacksAndMessages(null);
    }
}

Thread就介紹到這裡,明天來介紹Toolbar,明天見(. v . )
https://ithelp.ithome.com.tw/upload/images/20251009/20176154OYvlEfYZno.png


上一篇
Day24 TabLayout搭配ViewPager介紹
下一篇
Day26 Toolbar介紹
系列文
Android 菜鳥30天從0到1的學習紀錄27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言