I am building an application that downloads and displays several images. Everything is going well.
But i want it display an image as soon as it downloading. Not when its done downloading. I'm pretty sure it's called something like Interlaced, since i use PNGs.
This is part of code i've done to download and display an image :
private class DownloadTask extends AsyncTask<String, Integer, Bitmap> {
#Override
protected void onPostExecute(Bitmap result) {
ivGambar.setImageBitmap(result);// ivGambar is an ImageView
pbDetail.setVisibility(View.INVISIBLE);
}
#Override
protected Bitmap doInBackground(String... pa) {
try {
return BitmapFactory.decodeStream((InputStream) new URL(pa[0])
.getContent());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Is it can be done in Android? How?
Thank you.
I don't know exactly, but you can try to read progressively from the URL and then decode the stream even if it is incomplete, then doing it as you read from the stream, storing it in a buffer.
You can use URL.openStream() to get the stream, copy progressively the contents in a byte array (growing it if needed) and then use BitmapFactory.decodeByteArray to get the decoded partial bitmap (if the data is enough of course).
You could even use ByteArrayOutputStream as a buffer.
Be careful not to do this too often as it may slow down everything massively.
Related
Tried many ways in the internet but my imageView still display blank of the image.
Wish to retrieve the image from url (download or refer it) but seems I missed out something.
I have activated the INTERNET permission in manifest.
icon.setImageResource(R.drawable.portrait_user);
try {
URL url = new URL("https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xpf1/t1.0-1/c0.0.50.50/p50x50/1499583_10202305028778787_1063740680_n.jpg");
InputStream content = (InputStream)url.getContent();
Bitmap d = BitmapFactory.decodeStream(content);
icon.setImageBitmap(d);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Doing network I/O on the main application thread like this will crash your app on Android 4.0+.
Most likely, you will be better served using a third-party library that can download the image for you in the background and update the ImageView when it is ready. Picasso and Universal Image Loader are two of the more popular libraries for this.
I've this snippet of code which I would like to optimize it. I've a method which is been called regularly by the OSMdroid library to load tons of maptiles. This method directly invokes the filestream and load the bitmap directly and will return the bitmap once loaded on the main UI thread.
Although I've managed to run in the background using AsyncTask with parallel executor. Sometimes with plenty number of overlays (itemized) in the mapview this snippet of code runs slower as GC_FO_ALLOC is triggered regularly for allocation, and in my log messages I get Grow Heap (frag case). I tried many ways to work around, but not effective enough. For some reason this task is being executed on main thread is my feeling as in my log messages I also get Skipped xx frames, the application may be doing lot of task. Any idea how can this be made better? The thing is method has to return back, as soon as it loads, there by how can I allow this method to wait until mapview is not panned or zoomed, then load the tiles?
#SuppressWarnings("deprecation")
#Override
public Drawable getDrawable(final InputStream aFileInputStream) throws LowMemoryException {
try {
df = new DisplayFile();
df.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, aFileInputStream);
return new BitmapDrawable(df.get());
} catch (final OutOfMemoryError e) {
System.gc();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
private class DisplayFile extends AsyncTask<InputStream, Bitmap, Bitmap> {
InputStream path;
#Override
protected Bitmap doInBackground(InputStream... arg0) {
path = arg0[0];
BitmapFactory.Options mBitOpt = new BitmapFactory.Options();
mBitOpt.inDither = false;
mBitOpt.inSampleSize = 1;
mBitOpt.inPurgeable = true;
mBitOpt.inInputShareable = true;
mBitOpt.inPreferredConfig = Bitmap.Config.ARGB_8888;
final Bitmap mBitmap = BitmapFactory.decodeStream(path,null,mBitOpt);
return mBitmap;
}
}
As far as I understand, you are trying to display an offline map using osmdroid.
Android is unable to load "tons of map tiles" in memory, because it just doesn't provide enough memory heap to each application.
This is why osmdroid has advanced mechanisms (background loading, LRU cache, ...)
Why are you not just using these standard osmdroid mechanisms?
Look at this post for more details about off-line maps on osmdroid: Download maps for osmdroid
public class LoadImageActivity extends Activity {
ImageView image_view;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image_view = (ImageView)findViewById(R.id.imageview);
me m1=new me();
m1.execute("http://wallbase1.org/thumbs/rozne/thumb-499842.jpg");
me m2=new me();
m2.execute( "http://wallbase1.org/thumbs/rozne/thumb-637449.jpg");
me m3=new me();
m3.execute( "http://wallbase1.org/thumbs/rozne/thumb-2509834.jpg");
me m4=new me();
m4.execute( "http://wallbase1.org/thumbs/rozne/thumb-2501884.jpg");
me m5=new me();
m5.execute( "http://wallbase1.org/thumbs/rozne/thumb-2514440.jpg");
};
class me extends AsyncTask<String, Integer, Bitmap> {
Bitmap b1;
// private MainActivity m1;
protected Bitmap doInBackground(String...params) {
// TODO Auto-generated method stub
try {
/* Open a new URL and get the InputStream to load data from it. */
URL aURL = new URL(params[0]);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
/* Buffered is always good for a performance plus. */
BufferedInputStream bis = new BufferedInputStream(is);
/* Decode url-data to a bitmap. */
Bitmap bm = BitmapFactory.decodeStream(bis);
b1=bm;
bis.close();
is.close();
} catch (IOException e)
{
Log.e("DEBUGTAG", "Remote Image Exception", e);
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
image_view.setImageBitmap(b1);
Animation rotation = AnimationUtils.loadAnimation(LoadImageActivity.this, R.anim.rotate);
image_view.startAnimation(rotation);
}
}}
I am trying to show an image from internet by decoding it into bitmap,i want to show multiple images from multiple urls.Is there any better way of implementing it?
The duration of a download depends on a lot of different stuff. You currently spawn 5 AsyncTasks and there is no guarantee that the order of delivery/execution will be the same order you spawned them. It is easily possible that the fifth image might be the first you received and this would result in a totally wrong order. So you should download all images first, possibly with just one AsyncTask. After that and if that succeeded, you should start the animation and switch between the images.
There're several better ways of doing it and all of them are far more complex than your code. But you do have a good start.
This video form Google I/O have some good techniques for image, check around 4:40 https://www.youtube.com/watch?v=gbQb1PVjfqM
It takes different times because they are different images with probably different sizes.
Please post your XML R.anim.rotate code so someone can try to check why the animation is not working.
I have classic AsyncTask to load image:
private class DownloadImageTask extends AsyncTask<String,Void,Bitmap> {
Bitmap bitmap = null;
#Override
protected Bitmap doInBackground(String... str) {
try{
InputStream in = new java.net.URL(picture).openStream();
bitmap = BitmapFactory.decodeStream(new SanInputStream(in));
//viewPicture.setImageBitmap(bitmap);
viewPicture.setBackgroundDrawable(new BitmapDrawable(bitmap));
}
catch(Exception e){
e.printStackTrace();
}
return bitmap;
}
}
But loading of image is to long. When I start this activity, everything is loaded besides image and only after waiting a second I can see it. What is the problem?
viewPicture.setBackgroundDrawable(new BitmapDrawable(bitmap));
should be done on the UI thread, in the onPostExecute method of your AsyncTask.
Also, close the stream (if !null) you use with a nice finally block of your try/catch.
And don't worry about the time, it's the way to go.
Simple... because it takes time to open connection to the resource URL and download all the required bytes. Moreover, the performance may also vary on the speed of your Internet connection.
i've some leaks problems.
What i'm doing is loading some pictures in a table. I've created an asyncronous class for loading images.
In my table while i'm cycling the array I add my class
final LoaderImageView image = new LoaderImageView(getContext(),vgood[i].getImageUrl(),(int)(ratio *80),(int)(ratio *80));
row.addView(image);
In my asyncronous class i'm loading images from this
return Drawable.createFromStream(((java.io.InputStream)new java.net.URL(url).getContent()), "name");
Called by
public void setImageDrawable(final String imageUrl) {
mDrawable = null;
mSpinner.setVisibility(View.VISIBLE);
mImage.setVisibility(View.GONE);
new Thread(){
public void run() {
try {
mDrawable = getDrawableFromUrl(imageUrl);
imageLoadedHandler.sendEmptyMessage(COMPLETE);
} catch (MalformedURLException e) {
imageLoadedHandler.sendEmptyMessage(FAILED);
e.printStackTrace();
} catch (IOException e) {
imageLoadedHandler.sendEmptyMessage(FAILED);
e.printStackTrace();
}
};
}.start();
}
When i've a lot of images to load the app crashes due to out of memory caused by this line
return Drawable.createFromStream(((java.io.InputStream)new java.net.URL(url).getContent()), "name");
How can i fix that? where i'm going wrong?
thank you
Never load any tiles that you don't need. "am collecting all bitmaps from sdcard" suggests that you are decompressing every image you might ever need, which would be the wrong approach.
Use smaller tiles. 256x256 is a good size.
Load them as Config.RGB565 (i.e. 16bpp).
Regularly recycle() Bitmaps you don't need.
Basically you need to implement some sort of most-recently-used (MRU) Bitmap cache
Extrated From
Android: "java-lang-outofmemoryerror-bitmap-size-exceeds-vm-budget-android" While loading bitmaps from sdcard?