Bitmap too large to be uploaded into a texture exception

     今天做了一个demo,需求是一个scollerView里面嵌套一个图片,图片是一个长图,我用了imageView去设置图片,当图片加载完成后设置出现空白的问题,在

某些手机会但是有占位,某些手机就不会出现这问题。难过

    后来分析了一下,发现测试这个demo的手机只有1G内存,是不是内存不足?然后拿了另外一个1G内存的手机拿去测试,结果也发现了这个问题!!

   我猜想是内存不足的问题,就往这个方向去思考,后来看到log打印的时候出现一个警告warn:

Bitmap too large to be uploaded into a texture exception

然后后面有个最大值max = 4934*4934,还有该图片的大小734*5349,看英文意思很明显就是图片过大 了,于是copy这段话去百度了一下原因。

出错原因分析:

当开启硬件加速的时候,GPU对于openglRender 有一个限制,这个不同的手机会有不同的限制:

这个限制值可以通过canvas.getMaximumBitmapHeight()和canvas.getMaximumBitmapWidth()来获得。

安卓3.0之后图形绘制是需要硬件去辅助加速的,加速对图片大小是有限制的,这样手机进行操作时才会感觉流畅。


有一个最简单的解决办法是


<application android:hardwareAccelerated= "false" ...>去关闭硬件加速,这样虽然能解决问题,但是会导致滑动会特别卡,因为没有了硬件加速辅助。所以这个办法
不是很可行。找另外一种解决办法。。。。

安卓里面有一个类叫Bitmapregiondecoder类

BitmapRegionDecoder主要用于显示图片的某一块矩形区域,如果你需要显示某个图片的指定区域,那么这个类非常合适。

对于该类的用法,非常简单,既然是显示图片的某一块区域,那么至少只需要一个方法去设置图片;一个方法传入显示的区域即可;详见:

  • BitmapRegionDecoder提供了一系列的newInstance方法来构造对象,支持传入文件路径,文件描述符,文件的inputstrem等。

    例如:

    <code class="language-java hljs  has-numbering"> BitmapRegionDecoder bitmapRegionDecoder =
      BitmapRegionDecoder.newInstance(inputStream, <span class="hljs-keyword">false</span>);
    </code>
  • 上述解决了传入我们需要处理的图片,那么接下来就是显示指定的区域。

    <code class="language-java hljs  has-numbering">bitmapRegionDecoder.decodeRegion(rect, options);</code>

    参数一很明显是一个rect,参数二是BitmapFactory.Options,你可以控制图片的inSampleSize,inPreferredConfig

简单的说就是局部去加载大图,只是加载当前屏幕所显示的区域的大小的图片区域
在github上面下载了一个largeImagelib的工具类,里面封装了 bitmapRegionDecoder进行

包的项目结构是这样的

要加载长图只需用到他里面的自定义控件

<com.shizhefei.view.largeimage.LongImageView
    android:id="@+id/longimageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />
在代码里直接找到所对应的对象,然后得到图片解析的流进行set就可以显示巨图了
longimageView.setImage(in);
然后我们来分析下里面的源码。首先看setImage()方法

public void setImage(InputStream inputStream) {
   mScale.setScale(1);
   mScale.fromX = 0;
   mScale.fromY = 0;
   imageManager.load(inputStream);
}
里面封装了ImageManager进行加载。继续看下load方法

public void load(InputStream inputStream) {
   load(new InputStreamBitmapRegionDecoderFactory(inputStream));
}
private void load(BitmapRegionDecoderFactory factory) {
   release(this.mLoadData);
   this.mLoadData = new LoadData(factory);
   if (handler != null) {
      handler.removeCallbacksAndMessages(null);
      handler.sendEmptyMessage(MESSAGE_LOAD);
   }
里面创建了一个
BitmapRegionDecoderFactory对象,然后通过handler进行发送消息
看下发送消息到了哪里
if (msg.what == MESSAGE_LOAD) {
				if (loadData.mFactory != null) {
					try {
						loadData.mDecoder = loadData.mFactory.made();
						loadData.mImageWidth = loadData.mDecoder.getWidth();
						loadData.mImageHeight = loadData.mDecoder.getHeight();
						if (onImageLoadListenner != null) {
							onImageLoadListenner.onImageLoadFinished(loadData.mImageWidth, loadData.mImageHeight);
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
这个生成了一个BitmapRegionDecoder对象,然后把该对象的宽高赋给要加载的图片的宽高。回调了一个接口,然后在LargeImageView类里面进行
@Override
	public void onImageLoadFinished(int imageWidth, int imageHeight) {
		notifyInvalidate();
	}

进行绘制,
else {
				LargeImageView.this.post(runnable = new Runnable() {
					@Override
					public void run() {
						preInvalidateTime = SystemClock.uptimeMillis();
						runnable = null;
						Log.d("eeee", "preInvalidateTime:" + preInvalidateTime);
						invalidate(getVisiableRect());
					}
				});

绘制时要传入一个矩阵,调用了一个getVisiableRect()方法,看下此方法,

	protected Rect getVisiableRect() {
		Rect visiableRect = new Rect();
		getGlobalVisibleRect(visiableRect);
		int[] location = new int[2];
		getLocationOnScreen(location);
		visiableRect.left = visiableRect.left - location[0];
		visiableRect.right = visiableRect.right - location[0];
		visiableRect.top = visiableRect.top - location[1];
		visiableRect.bottom = visiableRect.bottom - location[1];
		return visiableRect;
	}
矩阵的边距根据屏幕动态改变的。在onDraw里面进行绘制图片,我们来看下onDraw里面调用了ImageManager一个方法


点进去看下,该方法传了一个缩放值跟一个Image的矩阵。然后再 看下该方法


通过handlerf发送一个消息,在这里接收

在这里进行解析,得到图片,通过接口回调出去解析不断绘制该图片。


猜你喜欢

转载自blog.csdn.net/zz6880817/article/details/50895192