Hoi,
also so grundlegend habe ich es auch, nur dass ich keine lokale Ressourcenliste habe, sondern immer in die DB greife.
Ich geh mal meine Reihenfolge der Aufrufe durch:
Ich baue eine ImageView und setze das Bild, wobei item.getImage() nur einen String liefert. Also die URL eigentlich.
ImageView iv = new ImageView(this);
iv.setAdjustViewBounds(true);
iv.setPadding(5, 5, 5, 5);
// prüfe, ob mein item (bean) ein Image hat
if (item.getImage() != null && !item.getImage().isEmpty()) {
ImageLoader.getInstance().displayImage(this, item.getImage(), iv, true);
} else {
iv.setImageResource(R.drawable.default_video);
}
Die displayImage sieht so aus
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, Runtime
.getRuntime().availableProcessors(), 1, TimeUnit.MINUTES, queue);
public void displayImage(Context context, String file, ImageView iv, boolean thumbnail) {
iv.setImageResource(R.drawable.nothumb);
ImageTask task = new ImageTask(context, file, iv, thumbnail);
task.executeOnExecutor(executor);
}
Alles anzeigen
Mein ImageTask ist nicht ganz konform, der hat irgendwie einen hau weg, ruft die onPostExecute nicht zuverlässig auf allen Devices auf, deshalb sieht er so aus
private class ImageTask extends AsyncTask<Void, Void, Void> {
private String file;
private ImageView iv;
private boolean thumbnail;
private Context context;
private Bitmap bitmap;
public ImageTask(Context context, String file, ImageView iv,
boolean thumbnail) {
this.file = file;
this.iv = iv;
this.thumbnail = thumbnail;
this.context = context;
}
@Override
protected Void doInBackground(Void... params) {
if (context == null || iv == null) {
return null;
}
PhotoHandler handler = PhotoHandler.getInstance(context);
if (!file.startsWith("http") && !file.startsWith("assets")) {
file = "assets://pictures/" + file;
}
byte[] blob = handler.getImage(file, thumbnail);
if (blob == null) {
if (file.startsWith("assets")) {
bitmap = Tools.getBitmapFromAsset(context, file, thumbnail);
} else {
bitmap = Tools.getImgeFromUrl(context, file, thumbnail);
}
handler.saveImage(file, bitmap, thumbnail);
} else {
bitmap = Tools.getImageFromBlob(blob);
blob = null;
}
setBitmap();
return null;
}
private void setBitmap() {
if (bitmap != null) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
iv.setImageBitmap(bitmap);
}
});
}
}
}
Alles anzeigen
Der handelt sowohl Online als auch Offline Bilder. Also welche, die im assets-Ordner liegen.
Mein PhotoHandler hat die getImage, die in die DB greift und den blob holt. Wenn der leer ist holt er sich das File vom assets bzw. von der URL frisch. Ich geh mal nur auf getImageFromUrl ein
public static Bitmap getImgeFromUrl(Context context, String url,
boolean thumbnail) {
if (!Tools.isOnline(context)) {
return null;
}
ImageDownloader id = new ImageDownloader(url, thumbnail);
Bitmap d = null;
try {
d = id.execute().get();
} catch (InterruptedException e) {
Log.e(Tools.class.getSimpleName(), e.getMessage());
} catch (ExecutionException e) {
Log.e(Tools.class.getSimpleName(), e.getMessage());
}
return d;
}
Alles anzeigen
das id.execute().get() hebelt zwar den AsyncTask etwas aus aber dem onPostExecute trau ich nicht mehr. Im ImageDownloader mach ich im Grunde das gleiche wie du, URLConnection aufbauen und Content abgreifen. Nur kleiner machen tu ich das Bild gleich, weil sonst später der RAM aus geht
is = (InputStream) response;
image = BitmapFactory.decodeStream(is);
is.close();
BitmapFactory.Options options = new BitmapFactory.Options();
options.outHeight = image.getHeight();
options.outWidth = image.getWidth();
int thumbwidth = -1;
int sampleSize = 1;
if (thumbnail) {
thumbwidth = (SplashScreen.deviceWidth - 40) / 3;
sampleSize = Tools.calculateInSampleSize(options,
thumbwidth, thumbwidth);
} else {
thumbwidth = (SplashScreen.deviceWidth - 40);
sampleSize = Tools.calculateInSampleSize(options,
thumbwidth, thumbwidth);
}
options.inSampleSize = sampleSize;
options.inDither = false;
options.inPreferQualityOverSpeed = false;
options.inPurgeable = true;
options.inJustDecodeBounds = false;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(CompressFormat.JPEG, 85, stream);
is = new ByteArrayInputStream(stream.toByteArray());
image.recycle();
image = BitmapFactory.decodeStream(is, null, options);
stream.close();
// den try-catch nöns lass ich mal weg, der wär hier noch dazwischen
return image;
Alles anzeigen
Das SplashScreen.deviceWidth und height lese ich ein mal im SplashScreen direkt am Anfang aus
Display display = SplashScreen.this.getWindowManager()
.getDefaultDisplay();
deviceWidth = display.getWidth();
deviceHeight = display.getHeight();
Ist deprecated, muss ich mal schaun, durch was ich das noch ersetze.
Meine Tools.calculateInSampleSize sieht so aus
protected static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
if (SplashScreen.memoryClass < 24) {
inSampleSize *= 2;
}
return inSampleSize;
}
Alles anzeigen
und ist aus irgend einem Forum entwendet
Ganz Ganz wichtig ist dann noch das image.recycle() vor dem zweiten decodeStream, weil ältere Android-Versionen (glaub unterhalb Honeycomb) das alte image nicht selbst recyclen, wenn die Variable überschrieben wird und man hat das Bild ein mal in zu groß im RAM und dann ein zweites mal Kleiner, womit der Sinn der Aktion dahin währe.
Glaub hab nix vergessen, also der Ansatz ist derselbe, wie du ihn jetzt auch verwirklicht hast. Nur hab ich extreme Probleme gehabt mit großen Bildern. Ich musste die aus Facebook auslesen und bekomm dort wenns blöd her geht ziemlich große Bilder. Facebook bietet jedes Bild zwar in glaub 9 verschiedenen Größen an, von dene auch das der deviceWidth entsprechend passendste genommen wird, nur kanns auch sein, dass das 1920x1080 oder so ist, da die Handys ja auch immer besser werden.
Sollte ich noch einen Codeschnipsel vergessen haben oder etwas unklar ist, meld dich
Gruß,
matze