首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 判斷「過了一個月」:天氣 APP 數據過期策略

     編輯:程式設計綜合問答

業務場景

天氣 APP 本地數據庫緩存天氣信息,Key 為城市名。需求:

  • 同城市一天內多次查詢走緩存。
  • 超過一天需重新請求網絡。
  • 若用戶手動修改系統時間,邏輯失效怎麼辦?

方案對比

方案實現優點缺點
本地時間比對存入時間戳,查詢時 System.currentTimeMillis() - savedTime > 24*3600*1000簡單、無網絡依賴用戶改系統時間即可繞過
服務器時間校驗App 啟動/定時請求 GET /api/time 獲取標準時間戳防作弊、統一標準需額外請求、離線不可用
網絡時間同步庫引用 NTPClient 或 OkHttp 獲取 HTTP Date 頭輕量、無需專用接口需網絡、精度受 RTT 影響
混合策略(推薦)優先用本地時間;關鍵操作(如付費數據)二次校驗服務器時間體驗與安全平衡邏輯稍複雜

推薦實現:混合策略 + 本地緩存服務器時間

public class TimeProvider {
    private static final long MAX_LOCAL_DRIFT = 5 * 60 * 1000; // 允許 5 分鐘漂移
    private long serverTimeOffset = 0; // serverTime - localTime
    private long lastSync = 0;

    // 應用啟動時異步同步
    public void syncServerTime() {
        OkHttpClient client = new OkHttpClient();
        Request req = new Request.Builder().url("https://api.example.com/time").build();
        client.newCall(req).enqueue(new Callback() {
            @Override public void onResponse(Call call, Response res) throws IOException {
                long serverMs = Long.parseLong(res.header("Date")); // 或 JSON 體
                serverTimeOffset = serverMs - System.currentTimeMillis();
                lastSync = System.currentTimeMillis();
            }
            @Override public void onFailure(Call call, IOException e) { /* 忽略,繼續用本地 */ }
        });
    }

    public long now() {
        // 若同步較近且漂移可控,用修正後時間
        if (System.currentTimeMillis() - lastSync < 24*3600*1000 && Math.abs(serverTimeOffset) < MAX_LOCAL_DRIFT) {
            return System.currentTimeMillis() + serverTimeOffset;
        }
        return System.currentTimeMillis(); // 回退本地
    }

    public boolean isExpired(long savedMs, long ttlMs) {
        return now() - savedMs > ttlMs;
    }
}

數據庫設計建議

CREATE TABLE weather_cache (
    city_id   TEXT PRIMARY KEY,
    data      TEXT NOT NULL,           -- JSON
    saved_at  INTEGER NOT NULL,        -- 服務器時間戳(毫秒)
    expires_at INTEGER NOT NULL        -- saved_at + TTL
);

查詢時:SELECT * FROM weather_cache WHERE city_id=? AND expires_at > ?(傳入 TimeProvider.now())。

「過了一個月」的處理

同理,只需將 TTL 設為 30L * 24 * 3600 * 1000。若需自然月(如 1 月 15 日 → 2 月 15 日),用 Calendar 運算:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(savedAt);
cal.add(Calendar.MONTH, 1);
long monthLater = cal.getTimeInMillis();

總結

  • 緩存過期判斷以服務器時間為準,本地時間僅作降級。
  • 啟動時異步同步時間,緩存偏移量,極低開銷。
  • 數據庫存儲絕對過期時間戳,查詢時直接比較,避免每行計算。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved