Mục tiêu
Tự động tạo instance Singleton mới mỗi 1 giờ để reset dữ liệu/cache, đảm bảo dữ liệu không bị lỗi thời.
Cách tiếp cận
Sử dụng Timer + TimerTask chạy nền, mỗi 1 giờ (3.600.000 ms) gán instance mới trong block synchronized để thread-safe.
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 (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/btnRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Refresh Singleton (Test)" />
</LinearLayout>
Bước 3: SingleTonExample.java với auto-refresh
package com.example.singletonrefresh;
import android.content.Context;
import java.util.Timer;
import java.util.TimerTask;
public class SingleTonExample {
// Instancevolatile để đảm bảo visibility giữa các thread
private static volatile SingleTonExample instance = new SingleTonExample();
private Context appContext;
// Static initializer: chạy 1 lần khi class load
static {
Timer timer = new Timer(true); // daemon thread
timer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (SingleTonExample.class) {
instance = new SingleTonExample(); // Tạo instance mới
// Instance cũ sẽ bị GC dọn dẹp nếu không còn reference
}
}
}, 60 * 60 * 1000L, 60 * 60 * 1000L); // delay 1h, period 1h
}
private SingleTonExample() {}
public static synchronized SingleTonExample getInstance() {
return instance;
}
public void init(Context context) {
if (appContext == null) {
this.appContext = context.getApplicationContext();
}
}
public static Context getGlobalContext() {
return getInstance().appContext;
}
// Thêm dữ liệu test
private String testData = "Instance tạo lúc: " + java.time.Instant.now();
public String getTestData() { return testData; }
}
Bước 4: MainActivity.java
package com.example.singletonrefresh;
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 btnRefresh;
private SingleTonExample singleton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnRefresh = findViewById(R.id.btnRefresh);
singleton = SingleTonExample.getInstance();
singleton.init(getApplicationContext());
btnRefresh.setOnClickListener(v ->
Toast.makeText(this, "Dữ liệu hiện tại: " + singleton.getTestData(), Toast.LENGTH_LONG).show()
);
}
}
Kết quả
Mỗi 1 giờ, instance Singleton tự động được thay thế. Nhấn nút test sẽ thấy timestamp thay đổi sau 1 giờ.


⚠️ Vấn đề & Giải pháp tốt hơn
Vấn đề với Timer trong Android:
- Timer có thể bị kill khi app vào background/doze mode
- Không bền vững qua reboot thiết bị
- Static initializer chỉ chạy 1 lần per process lifetime
Giải pháp Production: WorkManager
// Trong class Application.onCreate()
PeriodicWorkRequest refreshWork = new PeriodicWorkRequest.Builder(
SingletonRefreshWorker.class, 1, TimeUnit.HOURS)
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"singleton_refresh", ExistingPeriodicWorkPolicy.KEEP, refreshWork);
public class SingletonRefreshWorker extends CoroutineWorker {
@Override
public Result doWork() {
SingleTonExample.refreshInstance(); // static method tạo instance mới
return Result.success();
}
}
Thêm method refreshInstance() vào Singleton:
public static synchronized void refreshInstance() {
instance = new SingleTonExample();
}
Khi nào dùng auto-refresh Singleton?
- Cache token hết hạn (access token, refresh token)
- Dữ liệu cấu hình từ server thay đổi định kỳ
- Session user timeout
- Reset bộ nhớ đệm tránh memory leak