iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0

在第十七天,你已經對 MVVM 模式有了了解,知道 ViewModel 是一個介於 ViewModel 之間的「智慧助理」,可以讓程式碼變得更精簡、更好維護。

今天,我們要親自動手,製作一個最簡單的計數器 App,並用 MVVM 架構來實現它。這個專案會讓你清楚地看到 ViewViewModel 是如何分工合作的。

你的 App 專案

我們要製作一個 App:畫面上顯示一個數字,點擊按鈕後,數字會自動增加。 這個功能雖然簡單,但足以讓你體會 MVVM 的運作方式。

1. 修改你的 activity_main.xml

打開你的「設計圖」檔案 activity_main.xml。我們需要一個 TextView 來顯示數字,和一個 Button 來觸發增加。

`<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/counterTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="80sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.4" />

    <Button
        android:id="@+id/incrementButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="增加"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/counterTextView" />

</androidx.constraintlayout.widget.ConstraintLayout>`

2. 建立你的 ViewModel 類別

這是 MVVM 架構中的 ViewModel,它負責管理計數器的數字。

打開 MainActivity.java 所在的資料夾,右鍵點擊,選擇 New -> Java Class。給類別取名為 CounterViewModel

重點: ViewModel 類別必須繼承 androidx.lifecycle.ViewModel

`import androidx.lifecycle.ViewModel;

public class CounterViewModel extends ViewModel {

    // 這就是我們「智慧助理」要管理的資料
    private int counter = 0;

    // 取得目前數字的方法
    public int getCounter() {
        return counter;
    }

    // 增加數字的方法
    public void incrementCounter() {
        counter++;
    }
}

3. 修改你的 MainActivity.java (View)

  • MainActivity 現在變成了一個「被動」的角色,它只負責顯示畫面,並將使用者輸入轉交給 ViewModel
  • 重點: 我們會使用 ViewModelProvider 來創建或取得 ViewModel 的實例。
`import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.lifecycle.ViewModelProvider;

public class MainActivity extends AppCompatActivity {

    private TextView counterTextView;
    private Button incrementButton;
    private CounterViewModel viewModel; // 宣告 ViewModel 變數

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

        // 1. 取得或創建 ViewModel 實例
        viewModel = new ViewModelProvider(this).get(CounterViewModel.class);

        // 2. 找到 View 元件
        counterTextView = findViewById(R.id.counterTextView);
        incrementButton = findViewById(R.id.incrementButton);

        // 3. 從 ViewModel 取得初始數字並顯示
        counterTextView.setText(String.valueOf(viewModel.getCounter()));

        // 4. 設定按鈕點擊事件
        incrementButton.setOnClickListener(v -> {
            // 讓 ViewModel 執行增加數字的邏輯
            viewModel.incrementCounter();
            // 從 ViewModel 取得更新後的數字並更新畫面
            counterTextView.setText(String.valueOf(viewModel.getCounter()));
        });
    }
}`

4. 執行你的 App!

  • 點擊綠色的「」按鈕,執行 App。
  • 試著點擊「增加」按鈕,你會看到數字會隨著你的點擊而增加。
  • 關鍵體驗:在 App 運行時,試著旋轉你的模擬器或手機螢幕。你會發現數字不會回到 0!這就是 ViewModel 的魔力,它能讓資料在畫面的生命週期中存活下來。
    day18

今日總結

今天我們成功地完成了第一個 MVVM 專案!我們學會了:

  • 如何建立一個 ViewModel 類別,來管理畫面的資料和邏輯。
  • 如何在 MainActivity 中使用 ViewModelProvider 來取得 ViewModel 實例。
  • 親身體驗了 ViewModel 如何解決螢幕旋轉時資料流失的問題。

明天,我們要學習一個更強大的功能:LiveData。它能讓 View 自動觀察 ViewModel 的資料變化,從而實現自動更新畫面,讓你連手動更新 TextView 的程式碼都不用寫!

明天見!


上一篇
Day17- 更現代的架構!認識 MVVM 模式
下一篇
Day19- 讓畫面自動更新!認識 LiveData
系列文
Android 開發者養成計畫:從程式邏輯到作品集實戰22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言