Android开发-Application

一、Application 是什么?

Application 是 Android 四大组件之一(虽无需在 Manifest 中注册),代表整个应用进程

  • 创建时机 :在任何 ActivityService 启动前,由系统创建。
  • 生命周期:与应用进程生命周期一致,进程不退出,它就一直存在。
  • 全局唯一 :一个应用进程中只有一个 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();
}

⚠️ 注意 :简单状态可用,复杂状态建议用 ViewModelRepository

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 存入全局变量。
  • ✅ 优先使用 SharedPreferencesRoom 或内存缓存(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. 内存泄漏防护

  • ❌ 避免将 ActivityView 的引用存入 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

七、动手实践

  1. 创建 MyApplication,初始化一个日志库(如 Timber)。
  2. 实现 ActivityLifecycleCallbacks,打印应用前后台切换日志。
  3. 添加一个全局配置项(如 API Base URL),并通过 BuildConfig 动态设置。
  4. 实现一个简单的全局异常捕获器。

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
00后程序员张3 小时前
iOS 混淆与反调试反 Hook 实战,运行时防护、注入检测与安全加固流程
android·安全·ios·小程序·uni-app·iphone·webview
2501_915918413 小时前
iOS 上架流程详细指南 苹果应用发布步骤、ipa 文件上传 打包上架实战经验
android·ios·小程序·https·uni-app·iphone·webview
这次选左边3 小时前
Flutter混合Android开发Release 打包失败GeneratedPluginRegistrant.java,Plugin不存在
android·java·flutter
阿华的代码王国3 小时前
【Android】录制视频
android·音视频
啦工作呢3 小时前
ES6 promise-try-catch-模块化开发
android·okhttp
xiangxiongfly9155 小时前
Android 自定义View之BubbleImageView
android·气泡·bubbleimageview·气泡imageview
vivo高启强5 小时前
R8 如何优化我们的代码(2) -- 空值数据流分析
android
2501_916013745 小时前
iOS 26 系统电耗分析实战指南 如何检测电池掉电、液体玻璃导致的能耗变化
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_915921435 小时前
iOS 原生开发全流程解析,iOS 应用开发步骤、Xcode 开发环境配置、ipa 文件打包上传与 App Store 上架实战经验
android·macos·ios·小程序·uni-app·iphone·xcode