Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีประกาศตัวแปร Global (Singleton) ใน Android

ภาพรวม

ตัวอย่างนี้แสดงวิธีสร้าง Global Variable ที่เข้าถึงได้จากทุกที่ในแอป โดยใช้ Pattern Singleton ซึ่งเป็นวิธีที่แนะนำกว่าตัวแปร Static ธรรมดา

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project

ขั้นตอนที่ 2: Layout (res/layout/activity_main.xml)

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

    <TextView
        android:id="@+id/tvEvent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click to set global data"
        android:textSize="24sp"
        android:layout_marginBottom="16dp"/>

    <Button
        android:id="@+id/btnGetData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Global Data"/>

</LinearLayout>

ขั้นตอนที่ 3: สร้าง Singleton Class (SingleToneClass.java)

package com.example.globalvar;

public class SingleToneClass {

    private String data;
    private static final SingleToneClass INSTANCE = new SingleToneClass();

    // Private Constructor - ป้องกันการ new จากภายนอก
    private SingleToneClass() {}

    // Global Access Point
    public static SingleToneClass getInstance() {
        return INSTANCE;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }
}

ขั้นตอนที่ 4: MainActivity.java

package com.example.globalvar;

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

public class MainActivity extends AppCompatActivity {

    TextView tvEvent;
    Button btnGetData;

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

        tvEvent = findViewById(R.id.tvEvent);
        btnGetData = findViewById(R.id.btnGetData);

        // ตั้งค่าข้อมูล Global เมื่อคลิก TextView
        tvEvent.setOnClickListener(v -> {
            SingleToneClass instance = SingleToneClass.getInstance();
            instance.setData("This is global data from Singleton");
            tvEvent.setText("Data Set: " + instance.getData());
            Toast.makeText(this, "Global data saved", Toast.LENGTH_SHORT).show();
        });

        // อ่านข้อมูล Global
        btnGetData.setOnClickListener(v -> {
            String data = SingleToneClass.getInstance().getData();
            if (data != null) {
                tvEvent.setText("Global Data: " + data);
            } else {
                tvEvent.setText("No global data yet");
                Toast.makeText(this, "No data stored", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

ขั้นตอนที่ 5: Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.example.globalvar">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.GlobalVar">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

การทดสอบ

  1. รันแอป คลิก TextView "Click to set global data" - จะบันทึกข้อมูลและแสดงผล
  2. กดปุ่ม "Get Global Data" - จะอ่านข้อมูลจาก Singleton แสดงผล
  3. ลองเปิด Activity อื่น (ถ้ามี) - ข้อมูลยังคงอยู่

วิธีอื่นๆ และการเปรียบเทียบ

1. Application Class (แนะนำสำหรับ Global State จริง)

// MyApplication.java
public class MyApplication extends Application {
    private String globalData;

    public String getGlobalData() { return globalData; }
    public void setGlobalData(String data) { this.globalData = data; }
}

// Manifest
<application android:name=".MyApplication" ...>

// ใช้งาน
MyApplication app = (MyApplication) getApplication();
app.setGlobalData("data");

ข้อดี: ผูกกับ Application Lifecycle, เข้าถึงได้จากทุก Context, รองรับ DI (Hilt/Dagger)

2. Static Variable (ไม่แนะนำ)

public class Globals {
    public static String globalData = "initial";
}

ข้อเสีย: Memory Leak risk, ไม่ถูก Lifecycle จัดการ, ยากต่อ Testing, Thread Safety issue

3. SharedPreferences (Persistent)

// บันทึก
getSharedPreferences("prefs", MODE_PRIVATE).edit().putString("key", "value").apply();

// อ่าน
getSharedPreferences("prefs", MODE_PRIVATE).getString("key", "default");

ใช้เมื่อต้องการข้อมูลคงอยู่หลัง Kill App/Reboot

4. Dependency Injection (Hilt/Koin) - Modern Best Practice

// Hilt Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    @Singleton
    fun provideGlobalData(): MutableStateFlow<String> = MutableStateFlow("")
}

// ใช้งาน
@Inject lateinit var globalData: MutableStateFlow<String>

สรุป: เมื่อไหนควรใช้วิธีไหน

วิธีเหมาะสำหรับข้อควรระวัง
SingletonCache ชั่วคราว, Manager Class, Helperหายเมื่อ Process Death, ต้องจัดการ Thread Safety เอง
Application ClassGlobal State, Config, Repositoryเหมือน Singleton แต่ผูก Lifecycle
SharedPreferencesSettings, Token, User PreferencePersistent แต่ช้ากว่า (I/O)
Database (Room)Structured Data, Offline FirstComplex, Overkill สำหรับค่าเล็กๆ
DI (Hilt/Koin)โปรเจกต์ใหญ่, Testing, Scoped LifecycleSetup เริ่มต้นซับซ้อน