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

八、结语

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

相关推荐
沐怡旸9 小时前
【底层机制】LeakCanary深度解析:从对象监控到内存泄漏分析的完整技术体系
android·面试
又菜又爱coding9 小时前
Android + Flutter打包出来的APK体积太大
android·flutter
LiuYaoheng9 小时前
【Android】Drawable 基础
android·java
Jerry11 小时前
构建 Compose 界面
android
Y多了个想法11 小时前
Linux驱动开发与Android驱动开发
android·linux·驱动开发
2501_9160074714 小时前
从零开始学习iOS App开发:Xcode、Swift和发布到App Store完整教程
android·学习·ios·小程序·uni-app·iphone·xcode
姝然_952714 小时前
ConstraintLayout属性详解
android
2501_9160088915 小时前
前端工具全景实战指南,从开发到调试的效率闭环
android·前端·小程序·https·uni-app·iphone·webview
浅影歌年16 小时前
Android和h5页面相互传参
android
用户693717500138416 小时前
搞懂 Kotlin 软关键字与硬关键字:灵活命名与语法陷阱全解析
android