ImageView无法显示大尺寸图片求助(4128x3096)
解决大图片无法显示(白屏)的问题
看了你的代码和LogCat日志,核心问题已经很明确了:
Bitmap too large to be uploaded into a texture (3096x4128, max=4096x4096)
你的图片旋转后尺寸是3096×4128,刚好超过了OpenGL Renderer支持的最大纹理尺寸(4096×4096),导致无法将图片上传到GPU纹理,最终显示白屏。而1080×720的图片远小于这个限制,所以能正常加载。
下面是具体的解决方案,兼顾图片缩放适配纹理限制和填充显示到ImageView的需求:
步骤1:动态获取设备支持的最大纹理尺寸
不同设备的最大纹理尺寸可能存在差异,不要硬编码4096,我们可以通过代码动态获取:
private fun getMaxTextureSize(): Int { val display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY) val version = IntArray(2) EGL14.eglInitialize(display, version, 0, version, 1) val configAttrs = intArrayOf( EGL14.EGL_RED_SIZE, 8, EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_NONE ) val configs = arrayOfNulls<EGLConfig>(1) val configCount = IntArray(1) EGL14.eglChooseConfig(display, configAttrs, 0, configs, 0, configs.size, configCount, 0) val contextAttrs = intArrayOf( EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE ) val context = EGL14.eglCreateContext(display, configs[0], EGL14.EGL_NO_CONTEXT, contextAttrs, 0) EGL14.eglMakeCurrent(display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, context) val maxTextureSize = IntArray(1) GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0) EGL14.eglDestroyContext(display, context) EGL14.eglTerminate(display) return maxTextureSize[0] }
步骤2:计算合适的图片缩放比例
我们需要计算一个采样比例,让缩放后的图片宽高都不超过最大纹理尺寸,同时保留原有的宽高比:
fun calculateInSampleSize(options: BitmapFactory.Options, maxWidth: Int, maxHeight: Int): Int { val originalHeight = options.outHeight val originalWidth = options.outWidth var inSampleSize = 1 if (originalHeight > maxHeight || originalWidth > maxWidth) { val halfHeight = originalHeight / 2 val halfWidth = originalWidth / 2 // 找到最大的采样比例,确保缩放后尺寸不超过限制 while ((halfHeight / inSampleSize) >= maxHeight && (halfWidth / inSampleSize) >= maxWidth) { inSampleSize *= 2 } } return inSampleSize }
步骤3:整合缩放、旋转与ImageView填充显示
把上面的方法整合到你的加载逻辑里,先高效加载缩放后的图片,再处理旋转,最后设置填充显示:
val patchFile = "你的图片路径" val maxTextureSize = getMaxTextureSize() // 第一步:获取图片原始尺寸,不加载到内存 val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } BitmapFactory.decodeFile(patchFile, options) // 第二步:计算采样比例,加载缩放后的图片 options.apply { inJustDecodeBounds = false inSampleSize = calculateInSampleSize(options, maxTextureSize, maxTextureSize) inPreferredConfig = Bitmap.Config.RGB_565 // 降低内存占用,可选 } val bitmap = BitmapFactory.decodeFile(patchFile, options) // 第三步:处理图片旋转 val matrix = Matrix() matrix.postRotate(90F) val rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) // 第四步:设置ImageView为填充显示模式 imageView.scaleType = ImageView.ScaleType.CENTER_CROP // 按比例填充,裁剪超出部分 // 如果你不需要裁剪,也可以用FIT_XY:拉伸填充整个ImageView // imageView.scaleType = ImageView.ScaleType.FIT_XY imageView.setImageBitmap(rotatedBitmap) // 回收原始Bitmap,避免内存泄漏 bitmap.recycle()
额外处理:Toast线程警告问题
LogCat里还有一个关于Handler的警告:
Handler (android.widget.Toast$TN$2) {a8d7afe} sending message to a Handler on a dead thread
这是因为你在子线程中显示Toast后,线程提前销毁导致Toast的回调无法执行。解决方法是确保Toast在主线程显示,比如用runOnUiThread包裹:
runOnUiThread { Toast.makeText(this, "你的提示内容", Toast.LENGTH_SHORT).show() }
内容的提问来源于stack exchange,提问作者leprosychirp
相关产品推荐
相关产品推荐

