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. 实现一个简单的全局异常捕获器。

八、结语

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

相关推荐
2601_949833395 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
2603_949462107 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter
王泰虎9 小时前
安卓开发日记,因为JCenter 关闭导致加载不了三方库应该怎么办
android
2601_9495430112 小时前
Flutter for OpenHarmony垃圾分类指南App实战:主题配置实现
android·flutter
2601_9498333914 小时前
flutter_for_openharmony口腔护理app实战+知识实现
android·javascript·flutter
晚霞的不甘14 小时前
Flutter for OpenHarmony从基础到专业:深度解析新版番茄钟的倒计时优化
android·flutter·ui·正则表达式·前端框架·鸿蒙
鸟儿不吃草14 小时前
android的Retrofit请求https://192.168.43.73:8080/报错:Handshake failed
android·retrofit
Minilinux201814 小时前
Android音频系列(09)-AudioPolicyManager代码解析
android·音视频·apm·audiopolicy·音频策略
李子红了时15 小时前
【无标题】
android
Android系统攻城狮16 小时前
Android tinyalsa深度解析之pcm_close调用流程与实战(一百零四)
android·pcm·tinyalsa·音频进阶·音频性能实战·android hal