需求:在非 Activity/Service 元件(如工具類、靜態方法、第三方庫回調)中取得 Context。標準做法是**自訂 Application 子類別並在單例中持有 Context**。
public class MyApplication extends Application {
private static Context sContext;
@Override
public void onCreate() {
super.onCreate();
sContext = getApplicationContext(); // 應用層級 Context,生命週期最長
}
public static Context getContext() {
return sContext;
}
}
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- Activities... -->
</application>
// 工具類
public class Utils {
public static void showToast(String msg) {
Toast.makeText(MyApplication.getContext(), msg, Toast.LENGTH_SHORT).show();
}
public static SharedPreferences getDefaultPrefs() {
return PreferenceManager.getDefaultSharedPreferences(MyApplication.getContext());
}
}
| 決策點 | 推薦做法 | 理由 |
|---|---|---|
| 儲存哪種 Context | getApplicationContext() | 生命週期等同進程,不會洩漏 Activity、不受佈局膨脹影響 |
| 單例存取方式 | 靜態方法 getContext() | 簡單、無鎖、編譯期可見 |
| 是否需同步 | 不需 | onCreate() 在主執行緒單次執行,先於任何元件建立 |
| 是否可為 null | 理論上不可 | 但建議加 @Nullable 註解,呼叫端做空檢 |
static { sContext = ... } 會在類別載入時執行,早於 Application.onCreate(),必定為 null。ApplicationProvider.getApplicationContext()。大型專案建議使用 **Hilt (Dagger)** 或 **Koin** 管理 Context 依賴:
// Hilt
@AndroidEntryPoint
public class MyService extends Service {
@Inject Context context; // 自動注入 Application Context
}
// Koin
class MyRepository @Inject constructor(@Suppress("UNUSED_PARAMETER") @Context context: Context)
優點:編譯期檢查、易測試、支援作用域、避免全域單例濫用。
ApplicationContext,勿存 Activity Context。