Singleton Pattern là gì?
Singleton là design pattern đảm bảo một class chỉ có duy nhất 1 instance toàn ứng dụng. Dùng để: kiểm soát truy cập đồng thời, tạo điểm truy cập tập trung cho dữ liệu chia sẻ (cache, config, session...).
Mục tiêu
Tạo class Singleton chứa HashMap<String, Double> để lưu trữ dữ liệu key-value toàn cục, truy cập được từ bất kỳ đâu trong app.
Các bước thực hiện
Bước 1: Tạo dự án mới
Android Studio → File → New Project → Empty Activity.
Bước 2: Layout đơn giản (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp">
<Button
android:id="@+id/btnSaveHashMap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lưu HashMap vào Singleton" />
</LinearLayout>
Bước 3: Tạo class SingleTonExample.java
package com.example.singletonhashmap;
import android.content.Context;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SingleTonExample {
// Instance duy nhất (eager initialization - thread-safe)
private static final SingleTonExample INSTANCE = new SingleTonExample();
// Dữ liệu lưu trữ
private final Map<String, Double> dataMap = new HashMap<>();
private Context appContext;
// Private constructor ngăn tạo instance từ bên ngoài
private SingleTonExample() {}
// Điểm truy cập toàn cục
public static synchronized SingleTonExample getInstance() {
return INSTANCE;
}
// Khởi tạo context (gọi 1 lần trong Application hoặc MainActivity)
public void init(Context context) {
if (appContext == null) {
this.appContext = context.getApplicationContext(); // Dùng Application context tránh leak
}
}
// Lấy context toàn cục (dùng cho Toast, Resource, v.v.)
public static Context getGlobalContext() {
return getInstance().appContext;
}
// Thêm/cập nhật entry
public void put(String key, double value) {
dataMap.put(key, value);
}
// Lấy giá trị
public Double get(String key) {
return dataMap.get(key);
}
// Lấy toàn bộ map (để hiển thị/debug)
public String getHashMapString() {
return dataMap.toString();
}
// Xóa toàn bộ
public void clear() {
dataMap.clear();
}
}
Bước 4: MainActivity.java
package com.example.singletonhashmap;
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 Button btnSave;
private SingleTonExample singleton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSave = findViewById(R.id.btnSave);
singleton = SingleTonExample.getInstance();
singleton.init(getApplicationContext());
btnSave.setOnClickListener(v -> {
// Lưu dữ liệu vào Singleton
singleton.put("paper", 10.0);
singleton.put("recharge", 25.5);
singleton.put("other_bills", 100.0);
// Hiển thị kết quả qua Toast dùng global context
Toast.makeText(
SingleTonExample.getGlobalContext(),
"Đã lưu: " + singleton.getHashMapString(),
Toast.LENGTH_LONG
).show();
});
}
}
Kết quả
Nhấn nút → Toast hiển thị: Đã lưu: {paper=10.0, recharge=25.5, other_bills=100.0}


Best Practices cho Singleton Android
- Luôn dùng
context.getApplicationContext()để tránh memory leak Activity - Khởi tạo Singleton trong class
Application(overrideonCreate()) để sẵn sàng toàn app - Cân nhắc dependency injection (Hilt/Dagger) thay vì Singleton thủ công cho project lớn
- Thread-safety: HashMap không thread-safe → dùng
ConcurrentHashMapnếu multi-thread truy cập - Tránh lưu object nặng (Bitmap, Cursor) trong Singleton → OOM
Mở rộng: Singleton trong class Application
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
SingleTonExample.getInstance().init(this);
}
}
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
SingleTonExample.getInstance().init(this);
}
}Khai báo trong Manifest: <application android:name=".MyApp" ...>