Configuration(三)

本文详细剖析了MyBatis框架中Configuration对象的构建过程,包括XMLConfigBuilder如何通过parser.parse()方法将XML配置文件转化为Configuration对象,以及Configuration构造方法中的初始化设置。

上一篇文章中,我们找到了新的切入点Configuration,现在就让我们来看看parser.parse()是怎么样把xml配置文件转化成Configuration的.

我们先来看XMLConfigBuilder的构造方法:

  public XMLConfigBuilder(Reader reader, String environment, Properties props) {
    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
  }

  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

  // 这是XMLConfigBuilder父类构造方法,也就是super(new Configuration())
  public BaseBuilder(Configuration configuration) {
    this.configuration = configuration;
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
  }

其他的类我们不管,都是解析xml的类,不是本系列文章关注的重点,我们主要来看Configuration相关内容.可以看到在构造方法中new Configuration(),将实例化一个Configuration实例赋值给成员变量configuration.

我们来看看Configuration类的构造方法:

  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

  public Configuration() {
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

    languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
    languageRegistry.register(RawLanguageDriver.class);
  }

我们可以看到Configuration的构造方法中好像干了很多事情,其实就是进行了一些别名的默认设置,typeAliasRegistrylanguageRegistry内部都是封装了一个HashMap来存储数据.这些我们先不关注,我们先来看看parser.parse()方法:

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // 真正的处理逻辑,parser.evalNode("/configuration")获取了xml文件中最外层的<configuration>节点
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

  // 该方法中,将<configuration>下的所有节点分开处理,一个方法处理一个节点,理所当然,这些处理中肯定是对configuration成员变量中设置了所有配置文件中的信息.
  private void parseConfiguration(XNode root) {
    try {
      propertiesElement(root.evalNode("properties"));
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      settingsElement(root.evalNode("settings"));
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

接下来,我们将对每个方法,每个节点逐步进行分析.

<think>好的,用户想了解关于updateConfiguration方法的使用说明或错误解决。首先,我需要回忆一下Android开发中与配置变化相关的知识点。记得在Android中,当设备的配置发生改变时,比如屏幕旋转、语言切换等,默认情况下Activity会被销毁并重新创建。这可能影响用户体验,特别是当应用正在执行某些操作时。这时,开发者可能会使用android:configChanges属性来声明自行处理配置变化,避免Activity重建。 但根据引用[1],有些配置变化即使声明了也无法阻止应用重启。用户可能遇到了即使使用了android:configChanges,应用仍然重启的问题。需要解释哪些配置是无法被阻止的,比如字体大小变化、多窗口模式切换等。这部分需要详细说明,并给出正确的处理方式。 接下来,关于updateConfiguration方法。这个方法在Android API中用于更新设备的配置信息。例如,动态调整字体大小、语言设置等。但需要注意,这个方法在不同API版本中的行为可能不同。例如,在API 25及以上,使用Configuration.setTo()可能更推荐。需要说明如何使用这个方法,并提供代码示例,比如更新字体缩放因子后调用updateConfiguration,并提醒在API 17以上需要传入DisplayMetrics。 然后,常见的错误场景可能包括配置未正确应用、资源未刷新、API版本兼容性问题等。比如,修改配置后没有正确刷新资源,导致界面没有更新。需要指导用户使用recreate()方法来重新创建Activity,或者在合适的时机更新资源。同时,提醒在API 25及以上使用新的方法,避免过时的API调用。 用户的问题可能还涉及并发操作,比如在配置变化时处理数据版本的问题。引用[3]提到版本号变更导致update影响行数为0的情况,这可能与配置变化时的状态保存有关。需要建议用户使用ViewModel或onSaveInstanceState保存关键数据,防止配置变化导致数据丢失或版本不一致。 另外,引用[4]提到异步处理和Event事件开发,可能在配置变化时需要处理后台任务。比如,上传大文件时配置变化导致Activity重建,需要确保任务在后台继续运行,使用AsyncTask或WorkManager来管理。这部分需要结合配置变化的处理,建议用户使用保留的Fragment或ViewModel来保持任务不被中断。 总结需要回答的要点: 1. updateConfiguration方法的作用和使用方法,包括代码示例和版本差异。 2. 无法阻止应用重启的配置变化,解释android:configChanges的限制。 3. 常见错误及解决方法,如资源刷新、API兼容性、并发数据版本问题。 4. 处理配置变化时的异步任务管理,避免任务中断。 需要确保引用正确的文献,比如引用[1]提到某些配置变化无法阻止,引用[3]关于版本号变更的影响,引用[4]关于异步处理的方法。同时,保持回答结构清晰,分点说明,帮助用户逐步理解和解决问题。</think>### updateConfiguration 方法解析与常见问题解决 #### 一、方法作用与使用说明 `updateConfiguration` 是 Android 中用于动态更新设备配置的方法,常用于调整字体缩放比例、语言设置等场景。其基本语法如下: ```java // 获取当前配置 Configuration config = getResources().getConfiguration(); // 修改配置参数(例如字体缩放因子) config.fontScale = 1.2f; // 更新配置 getResources().updateConfiguration(config, getResources().getDisplayMetrics()); ``` - **适用场景**:动态修改语言、夜间模式切换、字体大小调整等[^1]。 - **API 版本差异**:在 API 25 (Android 7.1) 及以上,建议改用 `Configuration.setTo()` 方法结合 `Context.createConfigurationContext()` 实现更安全的配置更新[^2]。 #### 二、无法阻止应用重启的配置变化 即使通过 `android:configChanges` 声明了某些配置变化的处理(如 `orientation`),以下配置仍会强制重启应用: 1. **字体大小**(`fontScale`) 2. **多窗口模式**(分屏/画中画) 3. **系统语言**(非应用内切换) 此时需要配合 `onSaveInstanceState` 保存临时数据,并在 `onCreate` 中恢复。 #### 、常见错误与解决方法 1. **配置未生效** - **原因**:未正确刷新界面或资源。 - **解决**:调用 `recreate()` 重启 Activity,或手动更新 UI 组件: ```java textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.text_size)); ``` 2. **API 兼容性问题** - **现象**:`updateConfiguration` 在 API 25+ 失效。 - **解决**:改用新 API: ```java Configuration newConfig = new Configuration(config); newConfig.fontScale = 1.2f; Context context = createConfigurationContext(newConfig); // 使用新 Context 获取资源 Resources res = context.getResources(); ``` 3. **并发数据版本冲突** - **场景**:配置变化导致数据版本号变更(如数据库迁移)[^3]。 - **解决**:通过 `ViewModel` 或 `onRetainNonConfigurationInstance()` 保留关键数据: ```java public Object onRetainNonConfigurationInstance() { return currentData; // 返回需保留的对象 } ``` #### 四、异步任务处理建议 当配置变化时(如屏幕旋转),后台任务可能被中断。引用[^4]的异步化方案可参考: 1. **使用 `ViewModel` + `LiveData`** 持久化任务状态 2. **结合 `WorkManager`** 执行不受生命周期影响的后台任务 3. **通过 `onSaveInstanceState` 保存任务进度**(适合轻量级数据) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值