使用链式结构初始化Application 拒绝一般做法

本文介绍了一个名为Latte的配置初始化过程,包括如何设置API主机地址并完成配置。通过示例代码展示了配置步骤,并提供了Configurator类的具体实现。

mmp写的一遍不知道怎么回事 发表之后只有一半 不写了  直接上代码

public class ExampleApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Latte.init(this)
                .withApiHost("http://127.0.0.1/")
                .configure();
    }
}
public final  class Latte {
    public static Configurator init(Context context){
        getConfigurations().put(ConfigType.APPLICATION_CONTEXT.name(),context.getApplicationContext());
        return Configurator.getInstance();
    }


    public static WeakHashMap<String,Object> getConfigurations(){
        return Configurator.getInstance().getLatteConfigs();
    }
}
public class Configurator  {
    private static final WeakHashMap<String ,Object> LATTE_CONFIGS = new WeakHashMap<>();

    private Configurator(){
        LATTE_CONFIGS.put(ConfigType.CONFIG_READY.name(),false);
    }

    public static Configurator getInstance(){
        return Holder.INSTANCE;
    }
    private static class Holder{
        private static final Configurator INSTANCE = new Configurator();
    }

    final WeakHashMap<String ,Object> getLatteConfigs(){
        return LATTE_CONFIGS;
    }

    public final void  configure(){
        LATTE_CONFIGS.put(ConfigType.CONFIG_READY.name(),true);
    }

    public  final Configurator withApiHost(String host){
        LATTE_CONFIGS.put(ConfigType.API_HOST.name(),host);
        return this;
    }
    private  void  checkConfiguration(){
        final  boolean isReady = (boolean) LATTE_CONFIGS.get(ConfigType.CONFIG_READY.name());
        if (!isReady){
            throw  new RuntimeException("Configuration is not ready,call configure");
        }
    }

    final <T> T getConfiguration(Enum<ConfigType> key){
        checkConfiguration();
        return (T) LATTE_CONFIGS.get(key.name());
    }
}
public enum ConfigType {
    API_HOST,
    APPLICATION_CONTEXT,
    CONFIG_READY,
    ICON
}

<think>我们正在解决AndroidJUnitRunner初始化错误的问题。根据引用[1]中的错误信息,常见原因包括依赖冲突、配置错误或资源问题。以下步骤将帮助避免初始化错误: ### 步骤1:检查依赖冲突 在`build.gradle`中确保测试依赖版本一致: ```gradle dependencies { // 核心测试依赖 androidTestImplementation 'androidx.test:runner:1.5.2' androidTestImplementation 'androidx.test:rules:1.5.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // 确保JUnit版本兼容(引用[1]问题) testImplementation 'junit:junit:4.13.2' } ``` > 注意:避免同时引入`android.support.test`和`androidx.test`,这会导致冲突[^1]。 ### 步骤2:配置自定义TestRunner(如需要) 若需特殊初始化(如禁用某些库),创建自定义Runner: ```java // CustomTestRunner.java public class CustomTestRunner extends AndroidJUnitRunner { @Override public void onCreate(Bundle arguments) { arguments.putString("disableAnalytics", "true"); // 示例:禁用分析 super.onCreate(arguments); } @Override public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException, IllegalAccessException, InstantiationException { // 替换为测试专用Application(引用[2]的ARouter初始化思路) return super.newApplication(cl, "com.your.app.TestApplication", context); } } ``` ### 步骤3:处理初始化异常 在测试Application中捕获资源加载异常(引用[3]的定位SDK初始化思路): ```java // TestApplication.java public class TestApplication extends Application { @Override public void onCreate() { try { super.onCreate(); // 安全初始化第三方SDK ARouter.init(this); // 参考引用[2] } catch (Resources.NotFoundException e) { Log.e("TestApp", "Suppressed resource error", e); } } } ``` ### 步骤4:验证Gradle配置 在`build.gradle`中指定TestRunner: ```gradle android { defaultConfig { testInstrumentationRunner "com.your.app.CustomTestRunner" // 传递构建参数(引用[1]的构建配置思路) testInstrumentationRunnerArguments = [ "buildType": buildType.name ] } } ``` ### 步骤5:检查Manifest合并 确保`AndroidManifest.xml`正确声明Instrumentation(引用[4]的Activity声明模式): ```xml <manifest> <application ... > <!-- 测试相关组件 --> </application> <instrumentation android:name="com.your.app.CustomTestRunner" android:targetPackage="com.your.app" /> </manifest> ``` ### 常见错误解决方案 | 错误类型 | 解决方法 | |--------------------------|-------------------------------------------------------------------------| | `Resources.NotFoundException` | 在`callApplicationOnCreate()`中捕获异常(见步骤3) | | 初始化冲突 | 在测试Application中禁用自动初始化:`AppInitializer.disableComponent(...)` | | Mock框架异常 | 检查Mockito版本兼容性(引用[5]):`testImplementation "org.mockito:mockito-core:3.12.4"` | ### 验证流程 1. 清理构建缓存: ```bash ./gradlew clean :app:assembleDebugAndroidTest ``` 2. 运行测试: ```bash ./gradlew :app:connectedDebugAndroidTest ``` ### 相关问题 1. 如何解决测试中的`Resources$NotFoundException`? 2. 自定义TestRunner如何影响AndroidX测试库的行为? 3. 测试时如何动态禁用WorkManager初始化? 4. 不同构建变体(flavor)如何配置不同的Mock服务? 5. Android测试中如何安全初始化ARouter?[^2] 6. 为什么需要避免在测试中使用`android.support.test`?[^1] [^1]: 参考依赖冲突解决方案 [^2]: 基于ARouter的测试初始化实践</think>### 如何避免 AndroidJUnitRunner 初始化错误 以下是解决 AndroidJUnitRunner 初始化错误的完整方案,结合了常见错误原因和修复方法: #### 1. **解决依赖冲突(最常见问题)** ```gradle // build.gradle dependencies { // 确保使用兼容的测试库版本 androidTestImplementation 'androidx.test:runner:1.5.2' androidTestImplementation 'androidx.test:rules:1.5.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // 解决JUnit冲突(引用[1]) testImplementation 'junit:junit:4.13.2' // 统一版本 androidTestImplementation 'junit:junit:4.13.2' // 显式声明 // 强制排除冲突依赖 androidTestImplementation('androidx.test:runner') { exclude group: 'org.hamcrest', module: 'hamcrest-core' } } ``` > 关键操作:运行 `./gradlew :app:dependencies` 检查依赖树,解决版本冲突 #### 2. **正确配置测试专用组件** ```java // 测试专用Application(引用[2][3]) public class TestApp extends Application { @Override public void onCreate() { super.onCreate(); // 禁用生产环境初始化 disableProductionInitializers(); // 安全初始化测试所需SDK try { ARouter.init(this); // 路由框架示例 SDKInitializer.initialize(this); // 定位SDK示例 } catch (Exception e) { Log.e("TestApp", "SDK init failed", e); } } private void disableProductionInitializers() { // 禁用AndroidX自动初始化(引用[5]) AppInitializer.getInstance(this) .disableComponent(WorkManagerInitializer.class); } } ``` #### 3. **配置自定义TestRunner** ```java public class SafeTestRunner extends AndroidJUnitRunner { @Override public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException { // 强制使用测试专用Application return super.newApplication(cl, TestApp.class.getName(), context); } @Override public void callApplicationOnCreate(Application app) { // 捕获初始化异常(引用[3]) try { super.callApplicationOnCreate(app); } catch (Resources.NotFoundException e) { Log.w("TestRunner", "Suppressed resource error", e); } } } ``` ```gradle // build.gradle android { defaultConfig { testInstrumentationRunner "com.your.package.SafeTestRunner" // 添加测试参数(引用[1]) testInstrumentationRunnerArguments = [ "disableAnalytics": "true" ] } } ``` #### 4. **解决Manifest配置问题** ```xml <!-- src/androidTest/AndroidManifest.xml --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.your.package"> <application android:name=".TestApp" tools:replace="android:name"> <!-- 关键覆盖声明 --> <!-- 禁用不需要的组件 --> <meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" /> </application> <instrumentation android:name="com.your.package.SafeTestRunner" android:targetPackage="com.your.app" /> </manifest> ``` #### 5. **处理特殊框架初始化** ```java // 对于ARouter等框架(引用[2]) public void initRouter() { if (BuildConfig.DEBUG) { ARouter.openLog(); ARouter.openDebug(); } // 捕获可能的初始化异常 try { ARouter.init(this); } catch (Exception e) { Log.e("ARouter", "Init failed in test mode", e); } } ``` #### 6. **验证配置的正确性** ```bash # 检查Manifest合并结果 ./gradlew :app:processDebugAndroidTestManifest # 运行测试验证 ./gradlew :app:connectedDebugAndroidTest ``` ### 常见错误及解决方案 | **错误类型** | **解决方案** | |------------|------------| | `java.lang.NoClassDefFoundError` | 检查依赖冲突,使用`./gradlew :app:dependencies` | | `Resources$NotFoundException` | 在`callApplicationOnCreate()`中捕获异常 | | SDK初始化失败(如百度定位) | 在测试Application中安全初始化(引用[3]) | | `IllegalStateException: Failed to initialize plugin` | 检查Mockito版本兼容性(引用[5]) | | 路由框架初始化失败 | 禁用调试模式,捕获异常(引用[2]) | ### 关键预防措施 1. **隔离测试环境**:使用专用`TestApp`替代主Application 2. **异常防护**:在所有初始化操作中添加`try-catch` 3. **版本控制**:固定测试库版本(如`androidx.test:runner:1.5.2`) 4. **渐进式初始化**:分步初始化SDK,避免链式崩溃 ### 相关问题 1. 如何解决测试中的`java.lang.NoClassDefFoundError`错误? 2. 测试环境下如何安全初始化百度定位SDK?[^3] 3. 自定义TestRunner中如何禁用AndroidX自动初始化?[^5] 4. 不同构建变体(flavor)如何配置不同的测试初始化逻辑? 5. 如何捕获Android测试中的全局异常? 6. 测试覆盖率统计需要哪些特殊配置? [^1]: 依赖冲突解决方案 [^2]: ARouter测试初始化实践 [^3]: 百度定位SDK安全初始化 [^5]: 禁用AndroidX自动初始化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值