Android中超大圖片無(wú)法顯示的問題解決
發(fā)現(xiàn)問題
最近在做圖片瀏覽功能時(shí)遇到了一個(gè)很蛋疼的問題,在開啟硬件加速情況下,超大圖無(wú)法正常顯示(圖的長(zhǎng)寬有一個(gè)大于9000),而且程序不會(huì)crash,只是圖片加載不出來,View顯示為黑色。通過查看日志,發(fā)現(xiàn)系統(tǒng)打印出了下面的內(nèi)容:
W OpenGLRenderer( 4014): Bitmap too large to be uploaded into a texture (600x9518, max=8192x8192)
從日志內(nèi)容可以看出,這是由OpenGL打印出來的日志,是由于圖片的尺寸太大導(dǎo)致的。而且我們可以發(fā)現(xiàn),由于這個(gè)問題系統(tǒng)日志是以Warning級(jí)別打印出來的,并沒有拋出異常,程序并不會(huì)報(bào)錯(cuò),只是圖片顯示不出來,很難發(fā)現(xiàn)問題。當(dāng)我們把頁(yè)面的硬件加速關(guān)掉后,圖片就可以顯示出來了。
問題分析
從日志最后的內(nèi)容可以看出,OpenGL對(duì)圖片尺寸的限制是8192,這個(gè)尺寸是怎么得到的呢?是否所有的設(shè)備都是這個(gè)值呢?
要解釋這個(gè)問題,需要先來看一下GLES10中的一個(gè)常量GL_MAX_TEXTURE_SIZE
,從字面上看,它表示Texture的最大值。 查看文檔:
https://www.khronos.org/opengles/sdk/1.1/docs/man/glGet.xml
這里給出的解釋是: The value gives a rough estimate of the largest texture that the GL can handle。也就是OpenGL可以處理的最大尺寸的粗略估計(jì)值。既然是粗略估計(jì)值,那肯定是有一個(gè)準(zhǔn)確值的。
網(wǎng)上搜索了一下,基本上都是說通過執(zhí)行下面的代碼,可以得到這個(gè)準(zhǔn)確值。
int[] maxTextureSize = new int[1]; GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
然而,這段代碼在我的設(shè)備上運(yùn)行的結(jié)果始終是0。這是由于在Android 5.0之后,在進(jìn)行OpenGL方法的調(diào)用時(shí),需要手動(dòng)創(chuàng)建OpenGL的Context。而這個(gè)工作在5.0之前是由framework來完成的。我們這里就是因?yàn)闆]有創(chuàng)建這個(gè)Context導(dǎo)致調(diào)用結(jié)果為0。
那么有效的代碼就是下面這樣子的:
private void getGLESTextureLimitBelowLollipop() { int[] maxSize = new int[1]; GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); Toast.makeText(this," " + maxSize[0],Toast.LENGTH_LONG).show(); } private void getGLESTextureLimitEqualAboveLollipop() { EGL10 egl = (EGL10) EGLContext.getEGL(); EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] vers = new int[2]; egl.eglInitialize(dpy, vers); int[] configAttr = { EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER, EGL10.EGL_LEVEL, 0, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, EGL10.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]; int[] numConfig = new int[1]; egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig); if (numConfig[0] == 0) {// TROUBLE! No config found. } EGLConfig config = configs[0]; int[] surfAttr = { EGL10.EGL_WIDTH, 64, EGL10.EGL_HEIGHT, 64, EGL10.EGL_NONE }; EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr); final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; // missing in EGL10 int[] ctxAttrib = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL10.EGL_NONE }; EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib); egl.eglMakeCurrent(dpy, surf, surf, ctx); int[] maxSize = new int[1]; GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(dpy, surf); egl.eglDestroyContext(dpy, ctx); egl.eglTerminate(dpy); Toast.makeText(this," " + maxSize[0],Toast.LENGTH_LONG).show(); }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getGLESTextureLimitEqualAboveLollipop(); } else { getGLESTextureLimitBelowLollipop(); }
在我的5.0的手機(jī)上,執(zhí)行上面的代碼,得到這個(gè)最大值maxSize是16384,也就是說,當(dāng)圖片的長(zhǎng)和寬有一個(gè)超過這個(gè)值得時(shí)候,在開啟硬件加速的情況下,圖片就顯示不出來了。在不同的手機(jī)上運(yùn)行上述代碼,運(yùn)行結(jié)果不盡相同,說明這個(gè)值是設(shè)備相關(guān)的。
問題解決
既然知道了問題所在,下面就是想辦法來解決這個(gè)問題了。
首先,前面既然提到了是硬件加速導(dǎo)致的這個(gè)問題,最簡(jiǎn)單的方法當(dāng)然是關(guān)閉硬件加速,可以在Activity級(jí)別,也可以在View級(jí)別關(guān)閉硬件加速。這種是屬于簡(jiǎn)單粗暴型的。
Activity級(jí)別:
android:hardwareAccelerated="false"
View級(jí)別:
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
另外一種方法是通過縮小Bitmap的方式,保證圖片的尺寸不會(huì)超過OpenGL的限制,但是,對(duì)于查看高清圖的情況,不允許對(duì)圖片進(jìn)行縮放,這個(gè)方法是無(wú)效的。
最后也是最合理的方式,就是通過Android提供的BitmapRegionDecoder類來處理大圖加載。它的原理是每次只根據(jù)需要加載圖片的一部分,然后根據(jù)當(dāng)前用戶的操作去截取圖片不同部分進(jìn)行更新。具體的用法可以參考官方文檔。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)各位Android開發(fā)者們能有一定的幫助,如果有疑問大家可以留言交流。
- android 大圖片拖拽并縮放實(shí)現(xiàn)原理
- Android 實(shí)現(xiàn)WebView點(diǎn)擊圖片查看大圖列表及圖片保存功能
- Android高效加載大圖、多圖解決方案 有效避免程序OOM
- Android 實(shí)現(xiàn)加載大圖片的方法
- Android編程實(shí)現(xiàn)大圖滾動(dòng)顯示的方法
- Android 加載大圖、多圖和LruCache緩存詳細(xì)介紹
- Android實(shí)現(xiàn)網(wǎng)絡(luò)加載圖片點(diǎn)擊大圖后瀏覽可縮放
- Android實(shí)現(xiàn)大圖滾動(dòng)顯示效果
- Android仿頭條、微信大圖預(yù)覽視圖的方法詳解
相關(guān)文章
Android使用系統(tǒng)相機(jī)進(jìn)行拍照的步驟
這篇文章主要介紹了Android使用系統(tǒng)相機(jī)進(jìn)行拍照的步驟,幫助大家更好的進(jìn)行Android開發(fā),感興趣的朋友可以了解下2020-12-12Android?妙用TextView實(shí)現(xiàn)左邊文字,右邊圖片
這篇文章主要介紹了Android?妙用TextView實(shí)現(xiàn)左邊文字,右邊圖片的相關(guān)資料,需要的朋友可以參考下2023-07-07解決Android快速滑動(dòng)時(shí)圖片一閃一閃問題
這篇文章主要給大家介紹了個(gè)人在解決Android快速滑動(dòng)時(shí)圖片一閃一閃問題的一些思路和方法,非常實(shí)用,有需要的小伙伴可以參考下。2015-07-07Android開發(fā)SavedState?Jetpack狀態(tài)保存利器
這篇文章主要為大家介紹了Android開發(fā)SavedState?Jetpack狀態(tài)保存利器使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08Android 繪制多級(jí)樹形選擇列表實(shí)例代碼
這篇文章主要介紹了Android 繪制多級(jí)樹形選擇列表的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02Android Studio 新手入門教程(一)基本設(shè)置圖解
這篇文章主要介紹了Android Studio 新手入門教程(一)基本設(shè)置圖解,需要的朋友可以參考下2017-12-12Android開發(fā)中requestfocus()無(wú)效的原因及解決辦法
這篇文章主要介紹了Android開發(fā)中requestfocus()無(wú)效的原因及解決辦法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08