编辑一:
根据约瑟夫的回答所做的更改:
在 bytesToDrawable(byte[] imageBytes) 中:
更改了以下内容:使用 BitmapDrawable(Resources res, Bitmap bitmap) 而不是 BitmapDrawable(Bitmap bitmap):
return new BitmapDrawable(ApplicationConstants.ref_currentActivity.getResources(),BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options));
这是该更改的结果:略有不同的问题:
问题:
如果我将新的构造函数用于可绘制位图并缩放图像以达到所需的目标密度,我还需要使用我的 calculateSampleSize 方法吗?
原始问题:
嗨朋友们,
我的应用程序是基于模块的,因此特定于该模块的图像仅从包含它们的 jar(module) 加载,而不是从主应用程序加载。
每个模块都有自己的 ModularImageLoader - 它基本上允许我根据在 jar 中找到的图像名称来获取 Drawables。
构造函数接受 zipFile(Module A) 和文件名列表(zip 中以“.png”结尾的任何文件)。
进行的研究:
我使用了以下内容:Link to Developer Page on Loading bitmaps Effectively
最初我为每个密度创建大小的图像,但现在我只有一组大小为 96x96 的图像图标。
如果屏幕密度小于 xhdpi,我会加载 96x96 图像的较小采样尺寸 - 36x36(对于 ldpi)、48x48(对于 mdpi)、72x72(对于 hdpi)。否则我只返回 96x96 图像。(查看方法 calculateSampleSize() 和 bytesToDrawable())
我认为用代码更容易理解这个概念:所以这里是 ModularImageLoader
代码:
public class ModularImageLoader
{
public static HashMap<String, Drawable> moduleImages = new HashMap<String, Drawable>();
public static int reqHeight = 0;
public static int reqWidth = 0;
public ModularImageLoader(ZipFile zip, ArrayList<String> fileNames)
{
float sdpi = ApplicationConstants.ref_currentActivity.getResources().getDisplayMetrics().density;
if(sdpi == 0.75)
{
reqHeight = 36;
reqWidth = 36;
}
else if(sdpi == 1.0)
{
reqHeight = 48;
reqWidth = 48;
}
else if (sdpi == 1.5)
{
reqHeight = 72;
reqWidth = 72;
}
else if (sdpi == 2.0)
{
reqHeight = 96;
reqWidth = 96;
}
String names = "";
for(String fileName : fileNames)
{
names += fileName + " ";
}
createByteArrayImages(zip, fileNames);
}
public static Drawable findImageByName(String imageName)
{
Drawable drawableToReturn = null;
for (Entry<String, Drawable> ent : moduleImages.entrySet())
{
if(ent.getKey().equals(imageName))
{
drawableToReturn = ent.getValue();
}
}
return drawableToReturn;
}
private static void createByteArrayImages(ZipFile zip, ArrayList<String> fileNames)
{
InputStream in = null;
byte [] temp = null;
int nativeEndBufSize = 0;
for(String fileName : fileNames)
{
try
{
in = zip.getInputStream(zip.getEntry(fileName));
nativeEndBufSize = in.available();
temp = toByteArray(in,nativeEndBufSize);
// get rid of .png
fileName = fileName.replace(".png", "");
fileName = fileName.replace("Module Images/", "");
moduleImages.put(fileName, bytesToDrawable(temp));
}
catch(Exception e)
{
System.out.println("getImageBytes() threw an exception: " + e.toString());
e.printStackTrace();
}
}
try
{
in.close();
}
catch (IOException e)
{
System.out.println("Unable to close inputStream!");
e.toString();
e.printStackTrace();
}
}
public static byte[] toByteArray(InputStream is, int length) throws IOException
{
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int l;
byte[] data = new byte[length];
while ((l = is.read(data, 0, data.length)) != -1)
{
buffer.write(data, 0, l);
}
buffer.flush();
return buffer.toByteArray();
}
public static Drawable bytesToDrawable(byte[] imageBytes)
{
try
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
String imageType = options.outMimeType;
Log.d("ImageInfo : ", "Height:" + imageHeight +",Width:" +imageWidth + ",Type:" + imageType);
options.inJustDecodeBounds = false;
//Calculate sample size
options.inSampleSize = calculateSampleSize(options);
return new BitmapDrawable(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options));
}
catch(Exception e)
{
Message.errorMessage("Module Loading Error", "The images in this module are too large to load onto cell memory. Please contact your administrator",
"Source of error: ModularImageLoader - bytesToDrawable method", e.toString());
return null;
}
}
public static int calculateSampleSize(BitmapFactory.Options options)
{
// raw height and width of the image itself
int sampleSize = 1;
int height = options.outHeight;
int width = options.outWidth;
if(height > reqHeight || width > reqWidth)
{
if(width > height)
{
sampleSize = Math.round((float)height / (float)reqHeight);
}
else
{
sampleSize = Math.round((float)width / (float)reqWidth);
}
}
return sampleSize;
}
}
问题:
下图显示了 4 个正在运行的模拟器,这些是它们的规格以及我如何在 eclipse AVD 中设置它们:
LDPI:密度 120,皮肤 QVGA MDPI:密度 160,皮肤 HVGA HDPI:密度 240,皮肤 WVGA800 XHDPI:密度 320,皮肤 800x1280
图像显示问题:
问题:
根据代码 - 在 XHDPI 窗口中,为什么联系人图像如此之小?新闻图像也是 96x96(除了从主应用程序加载 - 所以它在 res>XHDPI 下)。问题是,我看到它在 MDPI 屏幕和 HDPI 屏幕上加载良好,但对于其他屏幕来说却很奇怪。有任何想法吗?