解决百度地图在模拟器上运行报 java.lang.IllegalArgumentException: No config chosen问题

解决百度地图在模拟器上运行报 java.lang.IllegalArgumentException: No config chosen 问题

1. 问题复现

在近期公司使用模拟器(网易MuMu)进行项目演示时,在进入存在百度地图(Android版本 7.4.2版本)之后,页面出现奔溃,后台日志为:

Back traces starts.
java.lang.IllegalArgumentException: No config chosen
com.baidu.platform.comapi.map.h$a.chooseConfig(GLTextureView.java:655)
com.baidu.platform.comapi.map.h$e.a(GLTextureView.java:789)
com.baidu.platform.comapi.map.h$f.l(GLTextureView.java:1164)
com.baidu.platform.comapi.map.h$f.run(GLTextureView.java:1002)

2. 查找源码,定位问题

经过问题的复盘,找到了是位于源码位置报错的:

com.baidu.platform.comapi.map.h$a.chooseConfig(GLTextureView.java:655)

具体代码位置如下:

com.baidu.platform.comapi.map.h

类下面的一个抽象类 a ,实现了EGLConfigChooser 接口,在实现chooseConfig接口时报错:

private abstract class a implements EGLConfigChooser {protected int[] a;public a(int[] configSpec) {this.a = this.a(configSpec);}public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {            // 代码省略... EGLConfig config = this.a(egl, display, configs);if (config == null) {throw new IllegalArgumentException("No config chosen");} else {return config;}}abstract EGLConfig a(EGL10 var1, EGLDisplay var2, EGLConfig[] var3);}

我们可以看到 EGLConfig这个类是由a方法返回的,我们可以看到,当config==null 时,会直接报出异常IllegalArgumentException,那么我们可以查看一下这个抽象类a是由谁来集成的?

通过搜索源码,它的继承方式是这样的:

package com.baidu.platform.comapi.map;public class h extends TextureView {private abstract class a implements EGLConfigChooser {}private class b extends com.baidu.platform.comapi.map.h.a {private int[] j = new int[1];protected int c;protected int d;protected int e;protected int f;protected int g;protected int h;public b(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) {super(new int[]{12324, redSize, 12323, greenSize, 12322, blueSize, 12321, alphaSize, 12325, depthSize, 12326, stencilSize, 12344});this.c = redSize;this.d = greenSize;this.e = blueSize;this.f = alphaSize;this.g = depthSize;this.h = stencilSize;}public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {EGLConfig[] var4 = configs;int var5 = configs.length;for(int var6 = 0; var6 < var5; ++var6) {EGLConfig config = var4[var6];int d = this.a(egl, display, config, 12325, 0);int s = this.a(egl, display, config, 12326, 0);if (d >= this.g && s >= this.h) {int r = this.a(egl, display, config, 12324, 0);int g = this.a(egl, display, config, 12323, 0);int b = this.a(egl, display, config, 12322, 0);int a = this.a(egl, display, config, 12321, 0);if (r == this.c && g == this.d && b == this.e && a == this.f) {return config;}}}return null;}private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : defaultValue;}}private class i extends com.baidu.platform.comapi.map.h.b {public i(boolean withDepthBuffer) {super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);}}}

综上所属,h下面的a,bi的关系为:

我们可以看到 h.c中其实没有a方法实现的,那么a方法的实现就是在h.b中了,我们可以来简单看一下h.b方法的实现:

        public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {EGLConfig[] var4 = configs;int var5 = configs.length;for(int var6 = 0; var6 < var5; ++var6) {EGLConfig config = var4[var6];int d = this.a(egl, display, config, 12325, 0);int s = this.a(egl, display, config, 12326, 0);if (d >= this.g && s >= this.h) {int r = this.a(egl, display, config, 12324, 0);int g = this.a(egl, display, config, 12323, 0);int b = this.a(egl, display, config, 12322, 0);int a = this.a(egl, display, config, 12321, 0);if (r == this.c && g == this.d && b == this.e && a == this.f) {return config;}}}return null;}private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : defaultValue;}

这里我们可以看到,当执行r == this.c && g == this.d && b == this.e && a == this.f为真时,才能返回对应的config对象,如果都不匹配,那么将会导致返回null·,今儿导致程序奔溃。问题找到了,我们应该怎么去改它呢?

3. 通过源码去修复它

我也不拐弯抹角了,经过对源码的分析,列举一下自己对这个问题修复的看法。首先,我们知道了问题所在的地方,那么我们是否在方法类b中的a方法永远不返回null,那样就不会导致出现No config chosen异常,虽然这种方法会导致所选择的EGLConfig和所需要的config不匹配,导致页面存在拉伸或者压缩的问题,但是这相比于奔溃,应该会好很多。那么就按照这个说的干吧。

首先,要修改返回值,使用它原有的逻辑肯定是不行的,但是我们返现这个 h.a抽象类实现的是 EGLConfigChooser,它是来自android.opengl.GLSurfaceView下的一个接口,比较熟悉openGL的人应该比较熟悉它:

    public interface EGLConfigChooser {/*** Choose a configuration from the list. Implementors typically* implement this method by calling* {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the* EGL specification available from The Khronos Group to learn how to call eglChooseConfig.* @param egl the EGL10 for the current display.* @param display the current display.* @return the chosen configuration.*/EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);}

那我能不能自定义一下我们的h.ah.bh.i类呢,把源码拷一遍,然后把a方法返回值修改一下即可,好,那么说干就干:

h.a类如下:

public abstract class ParentEGLConfigChooser implements GLSurfaceView.EGLConfigChooser {protected int[] a;public ParentEGLConfigChooser(int[] configSpec) {this.a = this.a(configSpec);}public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {int[] num_config = new int[1];if (!egl.eglChooseConfig(display, this.a, (EGLConfig[])null, 0, num_config)) {throw new IllegalArgumentException("eglChooseConfig failed");} else {int numConfigs = num_config[0];if (numConfigs <= 0) {throw new IllegalArgumentException("No configs match configSpec");} else {EGLConfig[] configs = new EGLConfig[numConfigs];if (!egl.eglChooseConfig(display, this.a, configs, numConfigs, num_config)) {throw new IllegalArgumentException("eglChooseConfig#2 failed");} else {EGLConfig config = this.a(egl, display, configs);if (config == null) {throw new IllegalArgumentException("No config chosen");} else {return config;}}}}}abstract EGLConfig a(EGL10 var1, EGLDisplay var2, EGLConfig[] var3);private int[] a(int[] configSpec) {int len = configSpec.length;int[] newConfigSpec = new int[len + 2];System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);newConfigSpec[len - 1] = 12352;newConfigSpec[len] = 4;newConfigSpec[len + 1] = 12344;return newConfigSpec;}}

对于h.b类,我们可以实现如下:

public class SubEGLConfigChooser extends ParentEGLConfigChooser {private final int[] j = new int[1];protected int c;protected int d;protected int e;protected int f;protected int g;protected int h;public SubEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) {super(new int[]{12324, redSize, 12323, greenSize, 12322, blueSize, 12321, alphaSize, 12325, depthSize, 12326, stencilSize, 12344});this.c = redSize;this.d = greenSize;this.e = blueSize;this.f = alphaSize;this.g = depthSize;this.h = stencilSize;}public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {BaseLog.i("----show the a------>>" + egl + "---->>" + display + "---->>" + Arrays.toString(configs));for (EGLConfig config : configs) {int d = this.a(egl, display, config, 12325);int s = this.a(egl, display, config, 12326);if (d >= this.g && s >= this.h) {int r = this.a(egl, display, config, 12324);int g = this.a(egl, display, config, 12323);int b = this.a(egl, display, config, 12322);int a = this.a(egl, display, config, 12321);if (r == this.c && g == this.d && b == this.e && a == this.f) {return config;}}}//TODO 直接修改这里,返回第一个 configs[0], 暂时还未发现任何异常return configs[0];}private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute) {return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : 0;}
}

同样,对于h.i类,我们可以自定义类为:

public class TargetEGLConfigChooser extends SubEGLConfigChooser{public TargetEGLConfigChooser() {super(8, 8, 8, 0, 16 , 0);}
}

这三个类我们已经写好了,那么如何将我们的TargetEGLConfigChooser 替换成目标h.i方法呢?这个可能要花一些时间,我们来大致了解一下 BaiduMap的基础架构,我们以 TextureMapView为例子:

TextureMapView是继承自ViewGroup, 它有一个私有属性值b,其类型为MapTextureView, 属性bTextureMapView的初始化方法中被初始化:

MapTextureView中,首先它是继承自com.baidu.platform.comapi.map.h的:

同时,我们在h类中找到了h,h是一个EGLConfigChooser类型的接口,

在这里插入图片描述

通过程序分析, 那么这个h的实现类就是咋们的h.i. 主要问题分析完成了,那么就好做了,直接使用反射,将我们的h的实现类直接由h.i替换成我们的 TargetEGLConfigChooser即可,代码很简单,就几行:

public class TextureMapViewFix {public static void tryToFixException(TextureMapView mapView) {try {Field b = mapView.getClass().getDeclaredField("b");  // 找到bb.setAccessible(true);Object bObject = b.get(mapView);BaseLog.i("bObject = " + bObject);if (null == bObject) {BaseLog.i("bObject is null and return");return;}Field h = bObject.getClass().getSuperclass().getDeclaredField("h"); //找到其父类,然后查找子元素hh.setAccessible(true);Object aObject = h.get(bObject);BaseLog.i("aObject = " + aObject);h.set(bObject, new TargetEGLConfigChooser());  //替换成咋们自定义的目标类  TargetEGLConfigChooserObject aObject1 = h.get(bObject);BaseLog.i("aObject1 = " + aObject1);  //检查是否更新成功}catch (Exception e) {e.printStackTrace();}}
}

4. 总结

可能baidu地图的源码是混淆的,所以啃起来不是特别的顺利,还是耐着性子看完了,问题其实并不复杂,弄清楚逻辑就比较简单了,可能就是java的反射需要点功底,其它的都好说。如果有任何问题,可以add v:javainstalling,备注:baidu.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/415957.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM工作原理与实战(二十):直接内存

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、直接内存 1.直接内存作用 二、在直接内存上创建数据 总结 前言 JVM作为Java程序的运行环境&#xff0c;其负责解释和执行字节码&#xff0c;管理内存&#xff0c;确保安全&…

【软件测试常见Bug清单】

软件测试中&#xff0c;bug的类型有很多种&#xff0c;比如&#xff1a;代码错误、界面优化、设计缺陷、需求补充和用户体验等&#xff1b; 一般情况下&#xff0c;需求补充和设计缺陷比较好区分&#xff0c;但是代码错误、界面优化和用户体验区分不是很明显&#xff1b; 下面…

23 SEMC外扩SDRAM

文章目录 23.1 SDRAM 控制原理23.2 SEMC 简介 23.1 SDRAM 控制原理 RT1052 系列芯片扩展内存时可以选择 SRAM 和 SDRAM 由于 SDRAM 的“容量/价格”比较高&#xff0c;即使用 SDRAM 要比 SRAM 要划算得多。 给 RT1052 芯片扩展内存与给 PC 扩展内存的原理是一样的 PC 上一般…

【C++干货铺】C++11常用新特性 | 列表初始化 | STL中的变化

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 C11简介 列表初始化 std::initializer_list std::initializer_list使用场景 decltype关键字 STL中的一些变化 新容器 array forward_list 容器中的一些新…

OpenSource - 工具管理器easy-manager-tool

文章目录 功能说明运行配置环境配置启动docker部署 项目安全UI展示 Easy-Manager-Tool 打造软件行业首款集成工具&#xff0c;不管你是程序员&#xff0c;测试&#xff0c;运维等都可以使用该软件来提升自己的工作效率。 Easy-Manager-Tool 的诞生是为了解决软件行业众多参与者…

HDR-HexPlane:首个针对高动态场景的HDR-NERF框架

导读&#xff1a; 本文提出了一种可以高效学习HDR动态场景的神经辐射场方法——HDR-HexPlane。在新视图合成方面&#xff0c;该模型可以考虑过曝和欠曝的颜色区域&#xff0c;在动态HDR场景数据集上取得了最先进的结果。 论文标题&#xff1a;Fast High Dynamic Range Radiance…

RK3568平台 LT9211转接芯片调试笔记

一.简介 龙讯LT9211是一个高性能转换器&#xff0c;支持MIPI LVDS TTL两两之间转换。 使用此款芯片大部分为MIPI与LVDS进行互相转换。 下图为LT9211的典型应用图&#xff1a; 二.LT9211原理图 三.车载显示器和摄像头系统 四.调试LT9211输出 MIPI数据 &#xff08;1&#xf…

【银行测试】银行项目,信用卡业务测试+常问面试(三)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行测试-信用卡业…

P3952 [NOIP2017 提高组] 时间复杂度————C++

目录 [NOIP2017 提高组] 时间复杂度题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 解题思路Code运行结果 [NOIP2017 提高组] 时间复杂度 题目背景 NOIP2017 提高组 D1T2 题目描述 小明正在学习一种新的编程语言 A&#xff0c;刚学会循环语句的他激动…

多测师肖sir___ui自动化测试po框架(升级)

ui自动化测试po框架&#xff08;升级&#xff09; po框架 一、ui自动化po框架介绍 &#xff08;1&#xff09;PO是Page Object的缩写&#xff08;pom模型&#xff09; &#xff08;2&#xff09;业务流程与页面元素操作分离的模式&#xff0c;可以简单理解为每个页面下面都有一…

西瓜书读书笔记整理(十一) —— 第十一章 特征选择与稀疏学习

第十一章 特征选择与稀疏学习 11.1 子集搜索与评价11.1.1 基本概念11.1.2 为什么要进行特征选择11.1.3 特征选择的两个关键环节11.1.4 常见的特征选择方法11.1.5 其他问题 11.2 过滤式选择11.2.1 什么是过滤式选择方法11.2.2 过滤式选择的优缺点 11.3 包裹式选择11.3.1 什么是包…

定时关机应用V2.1

# 在ShutDown_2.0的基础上&#xff0c;作了如下改进&#xff1a; # 1) 修正了默认模式无法选择其他时间的bug&#xff0c;还增加了2.5小时和3小时两个选项&#xff1b; # 2&#xff09;自定义模式将计时单位从“秒”改为“分钟”&#xff0c;倒计时显示也优化为“小时:分钟:秒”…