1つ編集:
ジョセフの答えに基づいて行われた変更:
bytesToDrawable(byte [] imageBytes):
以下を変更しました:BitmapDrawable(Bitmapビットマップ)の代わりにBitmapDrawable(Resources res、Bitmapビットマップ)を使用:
return new BitmapDrawable(ApplicationConstants.ref_currentActivity.getResources(),BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options));
これはその変更の結果です:わずかに異なる問題:
質問:
ビットマップドローアブルに新しいコンストラクターを使用していて、必要なターゲット密度に合わせて画像をスケーリングする場合でも、calculateSampleSizeメソッドを使用する必要がありますか?
元の質問:
よう皆、
私のアプリケーションはモジュールベースであるため、そのモジュールに固有の画像は、それらを含むjar(モジュール)からのみ読み込まれ、メインアプリケーションからは読み込まれません。
各モジュールには独自のModularImageLoaderがあります。これにより、基本的に、jarで見つかった画像の名前に基づいてDrawableをフェッチできます。
コンストラクターは、zipFile(モジュールA)とファイル名のリスト(zipから「.png」で終わるファイル)を受け取ります。
実施した調査:
私は以下を使用しました:ビットマップを効率的にロードするための開発者ページへのリンク
当初は密度ごとにサイズが設定された画像を作成していましたが、現在は96x96のサイズの画像アイコンが1セットだけあります。
画面密度が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つのエミュレーターを示しています。これらは、それらの仕様と、EclipseAVDでの設定方法です。
LDPI:密度120、スキンQVGA MDPI:密度160、スキンHVGA HDPI:密度240、スキンWVGA800 XHDPI:密度320、スキン800x1280
問題を示す画像:
質問:
コードに基づいて-XHDPIウィンドウで、連絡先の画像が非常に小さいのはなぜですか?ニュース画像も96x96です(メインアプリケーションからロードされたものを除いて、res> XHDPIの下にあります)。問題は、MDPI画面とHDPI画面では正常に読み込まれることですが、それ以外の場合は奇妙です。何か案は?