你的位置:首页 > 操作系统

[操作系统]ImageView的子类无法加载图片


在图片预览时,偶现图片无法现实,在查看程序的时候发现Bitmap是实际存在的,但是在ImageView中缺绘制不出来,这个问题困然了我很久,查看代码也查不出原因,再加上是偶现的,查原因时费了不少时间。

先来看看异常:

10-14 09:53:34.902  9003-10023/? W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (1024x9297, max=8192x8192)10-14 09:53:34.902  9003-10023/? W/OpenGLRenderer﹕ Shape too large to be rendered into a texture (940x8510, max=8192x8192)10-14 09:53:34.917  9003-10023/? W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (1024x9297, max=8192x8192)10-14 09:53:34.919  9003-10023/? W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (1024x9297, max=8192x8192)10-14 09:53:34.919  9003-10023/? W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (1024x9297, max=8192x8192)

 

其实是因为图片过长的原因,图片可以绘制的最大高度为8192,而我的图片高度为9297,在Canvas绘制时,OpenGL无法绘制出来,所以导致在预览长图时无法显示出来。

修改方式:

1.在异步加载图片时,判断图片的宽高,如果高度超出了底层OpenGL绘制的高度,那就把图片缩小。代码如下:

 1 public void loadImage(final MediaItem mediaItem) { 2     if (mBitmap == null && !mDestoryDecodeThread && !mDestory) { 3       mHardWareDecodeFuture = ThreadPool.getInstance().submit(new ThreadPool.Job<Bitmap>() { 4         @Override 5         public Bitmap run(ThreadPool.JobContext jc) { 6           boolean rotated = ((mediaItem.getRotation() / 90) & 1) == 1; 7           int photoWidth = rotated ? mediaItem.getHeight() : mediaItem.getWidth(); 8           int photoHeight = rotated ? mediaItem.getWidth() : mediaItem.getHeight(); 9           final BitmapFactory.Options options = new BitmapFactory.Options();10           jc.setCancelListener(new ThreadPool.CancelListener() {11             @Override12             public void onCancel() {13               options.requestCancelDecode();14             }15           });16           InputStream is = null;17           try {18             Bitmap bitmap = null;19             Uri uri = mediaItem.getContentUri();20             int sampleSize = 1;21             if (photoHeight > mHeight || photoWidth > mWidth) {22               final int heightRatio = (int) Math.floor((float) photoHeight / (float) mHeight);23               final int widthRatio = (int) Math.floor((float) photoWidth / (float) mWidth);24               sampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;25             }26             options.inSampleSize = sampleSize;27             if (bitmap != null) {28               options.inBitmap = bitmap;29             }30 31             if (uri.toString().startsWith("file://")) {32               bitmap = BitmapFactory.decodeFile(uri.toString().substring("file://".length(), uri.toString().length()), options);33             } else {34               is = getContext().getContentResolver().openInputStream(uri);35               bitmap = BitmapFactory.decodeStream(is, null, options);36             }37 38             /*重点缩小图片大小的代码*/39             int maxHeight = EglUtil.getMaxTextureSize(getContext());40             if (bitmap.getHeight() > maxHeight) {41               int w = bitmap.getWidth();42               int h = bitmap.getHeight();43               while (h > maxHeight) {44                 w = w / 2;45                 h = h / 2;46               }47               Bitmap b = Bitmap.createScaledBitmap(bitmap, w, h, true);48               bitmap.recycle();49               bitmap = b;50             }51             /**/52 53             if (jc.isCancelled() || mDestory || mDestoryDecodeThread) {54               WeakReference<Bitmap> ref = new WeakReference<Bitmap>(bitmap);55               return null;56             }57             return bitmap;58           } catch (Exception ex) {59           } finally {60             MediaItem.closeSilently(is);61           }62           return null;63         }64       }, new FutureListener<Bitmap>() {65         @Override66         public void onFutureDone(final Future<Bitmap> future) {67           if (future != null && future.get() != null) {68             post(new Runnable() {69               @Override70               public void run() {71                 mBitmap = future.get();72                 if (!mStopDrawBigBmp && !mDestoryDecodeThread && !mDestory) {73                   mScreenNailLoaded = true;74                   initBitmapRect();75                   invalidate();76                 } else {77                   if (mBitmap != null && !mBitmap.isRecycled()) {78                     mBitmap.recycle();79                   }80                 }81 82 83               }84             });85           }86         }87       });88     }89   }

2.判断图片是否超过绘制的最高高度。没一台手机,可绘制的最大高度是有可能不一样的,在Android5.0以上的版本中可以获取绘制的最大高度值,代码如下:

 1 public static int getMaxTextureSize(Context context){ 2     if(maxTextureSize != -1){ 3       return maxTextureSize; 4     } 5     maxTextureSize = 0; 6     int[] maxSize = new int[1]; 7     try { 8       ConfigurationInfo configurationInfo = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getDeviceConfigurationInfo(); 9       int glesVersion = configurationInfo.reqGlEsVersion;10       if(Build.VERSION.SDK_INT >= 21) {11         //configureEGLContext12         EGLDisplay mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);13         if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {14           throw new IllegalStateException("No EGL14 display");15         }16         int[] version = new int[2];17         if (!EGL14.eglInitialize(mEGLDisplay, version, /*offset*/ 0, version, /*offset*/ 1)) {18           throw new IllegalStateException("Cannot initialize EGL14");19         }20         int[] attribList = {21             EGL14.EGL_RED_SIZE, 8,22             EGL14.EGL_GREEN_SIZE, 8,23             EGL14.EGL_BLUE_SIZE, 8,24             EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,25             //EGL_RECORDABLE_ANDROID, 1,26             EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,27             EGL14.EGL_NONE28         };29         EGLConfig[] configs = new EGLConfig[1];30         int[] numConfigs = new int[1];31         EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,32             configs.length, numConfigs, /*offset*/ 0);33         if (EGL14.eglGetError() != EGL14.EGL_SUCCESS) {34           throw new IllegalStateException("eglCreateContext RGB888+recordable ES2" + ": EGL error: 0x" + Integer.toHexString(EGL14.eglGetError()));35         }36         int[] attrib_list = {37             EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,38             EGL14.EGL_NONE39         };40         EGLContext mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,41             attrib_list, /*offset*/ 0);42         if (EGL14.eglGetError() != EGL14.EGL_SUCCESS) {43           throw new IllegalStateException("eglCreateContext" + ": EGL error: 0x" + Integer.toHexString(EGL14.eglGetError()));44         }45         if (mEGLContext == EGL14.EGL_NO_CONTEXT) {46           throw new IllegalStateException("No EGLContext could be made");47         }48         int[] surfaceAttribs = {49             EGL14.EGL_WIDTH, 64,50             EGL14.EGL_HEIGHT, 64,51             EGL14.EGL_NONE52         };53         EGLSurface surface = EGL14.eglCreatePbufferSurface(mEGLDisplay, configs[0], surfaceAttribs, 0);54         EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);55         //getMaxTextureSize56         if(glesVersion >= 0x20000) {57           GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);58         }else if(glesVersion >= 0x10000) {59           GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);60         }61         //releaseEGLContext62         EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);63         EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);64         EGL14.eglReleaseThread();65         EGL14.eglTerminate(mEGLDisplay);66       }else {67         if(glesVersion >= 0x20000) {68           GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);69         }else if(glesVersion >= 0x10000) {70           GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);71         }72       }73     } catch (IllegalStateException e) {74       e.printStackTrace();75     }76     maxTextureSize = maxSize[0] > 0 ? maxSize[0] : DEFAULT_MAX_BITMAP_DIMENSION;77     return maxTextureSize;78   }

注意:以上获取最大高度值是在android5.0以上的版本才行。android5.0以下的版本使用:

private static final int DEFAULT_MAX_BITMAP_DIMENSION = 8196;

这样就能保证不管图片有多长,都能显示出来了。