一、Application 是什么?
Application
是 Android 四大组件之一(虽无需在 Manifest 中注册),代表整个应用进程。
- 创建时机 :在任何
Activity
、Service
启动前,由系统创建。 - 生命周期:与应用进程生命周期一致,进程不退出,它就一直存在。
- 全局唯一 :一个应用进程中只有一个
Application
实例。
📌 官方定义 :
Application
类在应用启动时被实例化,可用于执行全局初始化 和维护全局应用状态。
二、基本使用:自定义 Application
1. 创建自定义 Application
java
public class MyApplication extends Application {
private static MyApplication instance;
private String globalConfig;
private boolean isUserLoggedIn;
@Override
public void onCreate() {
super.onCreate();
// 应用创建时调用,仅一次
instance = this;
// 初始化操作
initCrashHandler();
initAnalytics();
initNetwork();
loadGlobalSettings();
}
@Override
public void onLowMemory() {
super.onLowMemory();
// 系统内存不足时调用,可在此释放非关键资源
Log.w("MyApp", "Low Memory Warning!");
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
// 更精细的内存释放回调
if (level >= TRIM_MEMORY_MODERATE) {
// 释放缓存等资源
}
}
// 提供全局上下文(谨慎使用)
public static MyApplication getInstance() {
return instance;
}
// 全局 Getter/Setter
public String getGlobalConfig() {
return globalConfig;
}
public void setGlobalConfig(String config) {
this.globalConfig = config;
}
public boolean isUserLoggedIn() {
return isUserLoggedIn;
}
public void setUserLoggedIn(boolean loggedIn) {
this.isUserLoggedIn = loggedIn;
}
}
2. 在 AndroidManifest.xml 中注册
XML
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- Activities, Services, etc. -->
</application>
✅ 必须注册 ,否则
onCreate()
不会被调用。
三、核心应用场景
1. 全局初始化(最常见用途)
在 onCreate()
中初始化第三方库,确保在任何组件使用前完成。
java
private void initAnalytics() {
// 如:友盟、Firebase、Bugly
AnalyticsKit.init(this);
AnalyticsKit.setChannel("google_play");
}
private void initNetwork() {
// 如:OkHttp, Retrofit
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
ApiService.init(client);
}
private void initCrashHandler() {
// 全局异常捕获
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
Log.e("Crash", "App crashed!", ex);
saveCrashLog(ex);
// 上报崩溃信息
CrashReport.postCatchedException(ex);
// 退出进程
android.os.Process.killProcess(android.os.Process.myPid());
});
}
2. 维护全局状态
存储应用级别的状态,避免频繁传递参数。
java
// 在登录 Activity 中
MyApplication app = (MyApplication) getApplication();
app.setUserLoggedIn(true);
// 在其他 Activity 中检查
if (((MyApplication) getApplication()).isUserLoggedIn()) {
showUserProfile();
}
⚠️ 注意 :简单状态可用,复杂状态建议用
ViewModel
或Repository
。
3. 提供全局上下文
java
// 在工具类中获取 Context
public class NetworkUtil {
public static boolean isNetworkAvailable() {
Context context = MyApplication.getInstance();
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnected();
}
}
⚠️ 风险:可能导致内存泄漏(见下文)。
4. 监听组件生命周期(Application.ActivityLifecycleCallbacks)
监控所有 Activity
的生命周期,用于埋点、会话统计等。
java
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
private int resumed = 0;
private int paused = 0;
@Override
public void onActivityResumed(@NonNull Activity activity) {
resumed++;
if (resumed == 1 && paused > 0) {
// 应用从后台回到前台
Log.d("Lifecycle", "App Brought to Foreground");
onAppForeground();
}
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
paused++;
if (resumed == paused) {
// 应用进入后台
Log.d("Lifecycle", "App Sent to Background");
onAppBackground();
}
}
// 实现其他回调...
@Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}
@Override public void onActivityStarted(@NonNull Activity activity) {}
@Override public void onActivityStopped(@NonNull Activity activity) {}
@Override public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}
@Override public void onActivityDestroyed(@NonNull Activity activity) {}
});
}
private void onAppForeground() {
// 如:刷新数据、重新连接 WebSocket
}
private void onAppBackground() {
// 如:断开非必要连接、保存状态
}
5. 多进程支持
如果应用有多个进程(如 :remote
),每个进程都会创建一个独立的 Application
实例。
XML
<service android:name=".RemoteService" android:process=":remote" />
java
@Override
public void onCreate() {
super.onCreate();
String processName = getProcessName();
Log.d("MyApp", "Application created in process: " + processName);
if (":remote".equals(processName)) {
// 仅在远程进程初始化特定服务
initRemoteService();
} else {
// 主进程初始化
initMainProcessComponents();
}
}
四、最佳实践与高级技巧
1. 避免滥用全局变量
- ❌ 不要将大量数据、Bitmap、Context 存入全局变量。
- ✅ 优先使用
SharedPreferences
、Room
或内存缓存(LruCache
)。
2. 懒加载与按需初始化
避免在 onCreate()
中执行耗时操作,阻塞 UI 启动。
java
private volatile boolean analyticsInited = false;
public void ensureAnalyticsInited() {
if (!analyticsInited) {
synchronized (this) {
if (!analyticsInited) {
new Thread(() -> {
// 耗时初始化
AnalyticsKit.init(this);
analyticsInited = true;
}).start();
}
}
}
}
3. 使用 ContentProvider 进行初始化(替代方案)
对于库的初始化,可使用 ContentProvider
避免依赖 Application
。
java
public class InitProvider extends ContentProvider {
@Override
public boolean onCreate() {
// 在应用启动时自动调用
MyLibrary.init(getContext());
return true;
}
// ... 其他方法返回 null
}
XML
<provider
android:name=".InitProvider"
android:authorities="${applicationId}.initprovider"
android:multiprocess="false"
android:exported="false" />
✅ 优点 :库无需用户继承
Application
。
4. 内存泄漏防护
- ❌ 避免将
Activity
或View
的引用存入Application
。 - ✅ 使用
WeakReference
包装长生命周期持有的对象。
java
private WeakReference<SomeListener> listenerRef;
public void setGlobalListener(SomeListener listener) {
this.listenerRef = new WeakReference<>(listener);
}
public SomeListener getGlobalListener() {
return listenerRef != null ? listenerRef.get() : null;
}
5. 配置多 flavor 的 Application
不同构建变体(如 debug, release)可使用不同的 Application
类。
Groovy
android {
flavorDimensions "version"
productFlavors {
dev {
applicationIdSuffix ".dev"
// 使用不同的 Application 类
manifestPlaceholders = [applicationClass: "com.example.DevApplication"]
}
prod {
manifestPlaceholders = [applicationClass: "com.example.ProdApplication"]
}
}
}
XML
<application
android:name="${applicationClass}"
... >
</application>
五、常见陷阱与解决方案
陷阱 | 后果 | 解决方案 |
---|---|---|
在 Application 中持有 Activity Context | 内存泄漏,Activity 无法回收 | 使用 getApplicationContext() |
onCreate() 执行耗时操作 | 应用启动慢,ANR 风险 | 异步初始化或懒加载 |
过度使用全局变量 | 内存占用高,状态混乱 | 用持久化存储或合理架构替代 |
未处理多进程 | 资源重复初始化,数据不一致 | 检查进程名,按需初始化 |
忘记注册 Application | 自定义逻辑不生效 | 检查 AndroidManifest.xml |
六、Application vs 其他组件
对比项 | Application | Activity | Service |
---|---|---|---|
生命周期 | 全局,最长 | 短暂,用户交互 | 中等,后台运行 |
唯一性 | 进程内唯一 | 可多个实例 | 可多个实例 |
用途 | 全局初始化、状态 | UI 界面 | 后台任务 |
Context 类型 | getApplicationContext() |
Activity Context |
Service Context |
七、动手实践
- 创建
MyApplication
,初始化一个日志库(如 Timber)。 - 实现
ActivityLifecycleCallbacks
,打印应用前后台切换日志。 - 添加一个全局配置项(如 API Base URL),并通过
BuildConfig
动态设置。 - 实现一个简单的全局异常捕获器。
八、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!