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

วิธีเก็บ Array ใน Singleton พร้อม Global Context ใน Android

Singleton สำหรับเก็บ Array และ Global Context

บทความนี้ขยายจาก Singleton Pattern เพื่อเก็บ Array (int[]) และให้เข้าถึง Global Context ได้จากทุกที่ในแอปพลิเคชัน ผ่าน method static getContext()

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

Android Studio → File → New Project → Empty Activity

ขั้นตอนที่ 2: Layout - activity_main.xml

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

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="24dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Singleton Array + Global Context"
            android:textSize="20sp"
            android:textStyle="bold"
            android:layout_marginBottom="16dp" />

        <Button
            android:id="@+id/btnSaveArray"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="บันทึก Array ลง Singleton"
            android:layout_marginBottom="12dp" />

        <Button
            android:id="@+id/btnShowArray"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="แสดง Array จาก Singleton (ใช้ Global Context)" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

ขั้นตอนที่ 3: Singleton Class - ArrayRepository.java

package com.example.singletonarraydemo;

import android.content.Context;
import android.util.Log;
import java.util.Arrays;

public class ArrayRepository {

    private static volatile ArrayRepository instance;
    private Context appContext;
    private int[] storedArray;

    private ArrayRepository() {}

    public static ArrayRepository getInstance() {
        if (instance == null) {
            synchronized (ArrayRepository.class) {
                if (instance == null) {
                    instance = new ArrayRepository();
                }
            }
        }
        return instance;
    }

    // Global Context Accessor - เรียกได้จากที่ไหนก็ได้: ArrayRepository.getInstance().getContext()
    public static Context getGlobalContext() {
        return getInstance().appContext;
    }

    public void init(Context context) {
        if (appContext == null) {
            this.appContext = context.getApplicationContext();
            Log.d("ArrayRepository", "Context initialized");
        }
    }

    public void storeArray(int[] array) {
        this.storedArray = array != null ? array.clone() : new int[0];
    }

    public int[] getArray() {
        return storedArray != null ? storedArray.clone() : new int[0];
    }

    public String getArrayString() {
        return Arrays.toString(storedArray);
    }

    public void clear() {
        storedArray = new int[0];
    }
}

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

package com.example.singletonarraydemo;

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

public class MainActivity extends AppCompatActivity {

    private ArrayRepository repository;
    private Button btnSave, btnShow;
    private final int[] sampleArray = {33, 12, 98, 45, 67, 23};

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

        repository = ArrayRepository.getInstance();
        repository.init(getApplicationContext());

        btnSave = findViewById(R.id.btnSaveArray);
        btnShow = findViewById(R.id.btnShowArray);

        btnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                repository.storeArray(sampleArray);
                Toast.makeText(MainActivity.this, "บันทึก Array แล้ว: " + Arrays.toString(sampleArray), Toast.LENGTH_SHORT).show();
            }
        });

        btnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // ใช้ Global Context จาก Singleton โดยตรง
                Context globalContext = ArrayRepository.getGlobalContext();
                String arrayString = repository.getArrayString();
                Toast.makeText(globalContext, "ข้อมูลจาก Singleton: " + arrayString, Toast.LENGTH_LONG).show();
            }
        });
    }
}

การใช้งาน Global Context ในคลาสอื่น

// ในคลาสอื่นๆ ใดๆ ที่ไม่ใช่ Activity/Service
public class SomeHelperClass {
    public void doSomething() {
        Context context = ArrayRepository.getGlobalContext();
        if (context != null) {
            // ใช้ context ได้เลย เช่น
            // SharedPreferences prefs = context.getSharedPreferences(...);
            // Resources res = context.getResources();
            // context.startActivity(intent); // ต้องเพิ่ม FLAG_ACTIVITY_NEW_TASK
        }
    }
}

⚠️ ข้อควรระวังในการใช้ Global Context

ปัญหาคำอธิบายแก้ไข
Memory Leakถ้าเก็บ Activity Context แทน Application Contextใช้ context.getApplicationContext() เสมอ
Null Contextเรียกก่อน init() หรือหลัง Process ถูก KillCheck null ก่อนใช้, เริ่มต้นใน Application class
Start ActivityApplication Context ไม่สามารถ startActivity() ได้โดยตรงเพิ่ม intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Dialog/Toastทำงานได้แต่ควรใช้ Activity Context สำหรับ Dialogส่ง Activity context เข้า method แทน

Best Practice: เริ่มต้นใน Application Class

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Initialize Singleton ทุกตัวที่ต้องการ Context ที่นี่
        ArrayRepository.getInstance().init(this);
        DataRepository.getInstance().init(this);
    }
}

AndroidManifest.xml: <application android:name=".MyApp" ...>

ขยายเป็น Generic Array Repository

public class GenericArrayRepository<T> {
    private static volatile GenericArrayRepository instance;
    private T[] array;
    
    private GenericArrayRepository() {}
    
    public static GenericArrayRepository getInstance() { ... }
    
    public void setArray(T[] array) {
        this.array = array != null ? array.clone() : null;
    }
    
    public T[] getArray() {
        return array != null ? array.clone() : null;
    }
}

สรุป

Singleton ที่ให้ Global Context และเก็บ Array ได้ ช่วยลดการส่ง Context ผ่าน Constructor หลายชั้น แต่ต้องระวัง Memory Leak และ Null Context ควร Initialize ใน Application Class และใช้ Application Context เท่านั้น