问题描述:
GLSurfaceView中通过纹理绘制图形,纹理长宽为2的幂次(128*64)。资源放在res/drawable文件夹下面。发现在hdpi手机上图形为白色,还有同事手机上是黑色。
初步判断:
可能原因是纹理丢失。。导致绘制图形采用默认颜色绘制:白色或者黑色,结果随机。
为什么纹理丢失呢?我直接把问题归咎于奇葩的android,感觉hdpi手机优先搜索drawable-hdpi文件夹,并没有搜索drawable目录??
问题排查:
步骤1:通过图片资源上传gl前,将图片保存到磁盘。结果发现图片确实被搜索到。否定了之前的猜测。
步骤2:图片上传gl时,打log输出图片尺寸。结果惊人地发现hdpi手机上图片大小变为192*96。。看来是因为图片尺寸不是2的幂次导致纹理创建失败。真的有文章。
步骤3:于是我将尺寸为128*64的资源拷贝到res/drawable-hdpi下,再次运行程序。结果发现纹理创建成功,图形绘制正确,输出图像尺寸正确为128*64。
原因定位:为什么前后两种情况图像尺寸会变化呢?计算了一下,恰好长宽相差1.5倍,想起了android的多分辨率规则:3:4:6:8。 正常分辨率手机为1,ldpi手机需要缩小为0.75,hdpi手机需要拉伸到1.5,xhdpi手机需要拉伸到2.0。对Android这个自作多情地隐式操作真无语。
结论:
正常情况下图片资源需要放在res/drawable,res/drawable-ldpi,res/drawable-hdpi,res/drawable-xhdpi,且不同分辨率文件夹下都需要放置一份。对于适配gles1.0特意制作的大小为2的幂次的资源,为了防止android隐式缩放,尤其需要在不同分辨率文件夹下放置一份相同的拷贝。然后通过资源加载原始bitmap:
Bitmap mMarkerBmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.bus_subway);
对于不希望被拉伸地资源,更好地方式直接放在assets目录下,通过文件方式加载资源:
protected Bitmap readBitmapFromAssets(String filename) {
InputStream istr;
try {
istr = mapView.getContext().getAssets().open(filename);
} catch (IOException e) {
istr = null;
return null;
}
return BitmapFactory.decodeStream(istr);
}
想到了其他与本文无关的点,1.通过纹理坐标也可以DIY android 的9patch效果;2. png图像是LZW无损压缩算法,难怪android这么提倡使用png。