I am having trouble loading a bitmap from a url on Android based on this answer: https://stackoverflow.com/a/8993175/1062794
I've simplified the case to the absolute minimum:
public void loadBitmap(View view) {
Bitmap b = getBitmapFromURL("http://upload.wikimedia.org/wikipedia/en/7/70/Example.png");
}
public Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
I have enabled internet access in manifest (I believe):
<uses-permission android:name="android.permission.INTERNET"/>
When I run the app it crashes with null details when it tries to run connection.connect(). Stepping through I see it tries to throw this error from StrictMode.class:
if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
throw new NetworkOnMainThreadException();
}
This is my first day trying to make an Android app so I could be making an obvious mistake. I am using the emulator and Win7.
Starting with Android 3.0, synchronous operations can no longer be run directly from a UI thread. If you try to call the loadBitmap(View view) method directly in your onCreate() method, your application will crash when it is run on a device running Android 3.0 and later. Because loadBitmap() method is synchronous - that is, it will not return control until the image is downloaded - calling it directly will freeze the UI of your activity. This is not allowed in Android 3.0 and later; all synchronous code must be wrapped using an AsyncTask class. Using AsyncTask enables you to perform background tasks in a separate thread and then return the result in a UI thread. That way, you can perform background operations without needing to handle complex threading issues. To call the loadBitamp() method asynchronously, you need to wrap the code in a subclass of the AsyncTask class, as shown here:
private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return getBitmapFromUrl(urls[0]);
}
protected void onPostExecute(Bitamp result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}
Now in the onCreate() method create a new instance of AsyncTask class and execute it:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadImage().execute("http://upload.wikimedia.org/wikipedia/en/7/70/Example.png");
}
this is because you are trying to access the internet from the ui thread (more info here) .
create a new thread (you can use an asyncTask if you wish, but any other thread creation method would suffice) in order to access the internet , and once the bitmap is ready , pass it to the ui thread if you wish to show it
also , for a nice sample of bitmap handling read this :
http://developer.android.com/training/displaying-bitmaps/index.html
Your void will crash when image size big 5 MG. Bitmap are stacking RAM so sample 20 images * 5 = 100 mb. When you re open activity another 100 mb spend your RAM and app will crash. You add follow lines your code;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
options.inSampleSize = 2;
Bitmap myBitmap = BitmapFactory.decodeStream(input,rect,options);
Related
I have an activity in which the user presses a button which fetches a JSON response from a URL, and then downloads and saves all of the image URLs in that JSON. The downloading takes place in a separate class which extends Thread:
downloadButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DownloadTask task = new DownloadTask(handler);
task.start();
}
});
handler is an inner static Handler that holds a WeakReference to the activity (used for displaying progress).
In the DownloadTask:
public DownloadTask(Handler handler) {
this.handler = handler;
}
#Override
public void run() {
String jsonString = // gets JSON from server
urlsToDownload = new HashSet<String>();
// do some stuff with the JSON to put each URL into the Set
for (Iterator<String> i = urlsToDownload.iterator(); i.hasNext(); ) {
String urlString = i.next();
// the following takes place in two static method calls,
// but I've laid it all out here for easier interpretation.
// I'm also removing all try/catch blocks, if (x != null) checks etc
// first download the image from the web
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
Bitmap bitmap = BitmapFactory.decodeStream(bis);
bis.close() // (done in try-with-resource)
connection.disconnect();
// then save the image on the device
File file = new File(App.context.getFilesDir(), "my/file/name.jpg");
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.close() // (done in try-with-resource)
// make a Bundle, add some progress info and send it in a Message
handler.handleMessage(msg);
}
}
My problem is that this is using a very large amount of memory. When looking at the memory monitor in Android Studio, it spikes up to ~95MB when downloading/saving each image (~1.7MB). I used the allocation tracker to take a close look, and there is this one line which bothers me:
Can anyone help me figure out why this is happening? As far as I know, this is a "standard" way to download images in Android.
You make intermediate Bitmaps from your files. That takes a lot of memory. Do not use Bitmaps but save the image bytes directly to file. You are probably downloading a jpg file i think.
Just make a loop in which you read chunks from the input stream and write them to the file output stream.
I have an app where I have one banner in the top with News, when I want to put other news I need to open the code and change the resource .jpg and the Link. There is a way to change the banner and the Link (or at least the banner) without modifing the code? Idk maybe uploading it to a webpage or something like this.
thanks
My suggestion would be to upload a banner.jpg to a server that your app can access and dynamically load. This would prevent having to update your app every time you want to change the banner, and makes it cleaner (no excessive Google Play updates). To do actually load the image you can use this code:
ImageView image1 = (ImageView) findViewById(R.id.mybanner);
new Thread(new Runnable(){//create a new thread so we can do network operations
#Override
public void run() {//main thread function
try {//attempt to do network stuff
URL url = new URL("http://your-hosting-site.com/banner.jpg");//create aURL object with the path to your banner
HttpURLConnection con = (HttpURLConnection) url.openConnection();//create the connection object from the url
con.setReadTimeout(15000);
con.setConnectTimeout(15000);
con.setRequestMethod("GET");
con.setDoInput(true);
con.connect();//connect to the server
InputStream is = con.getInputStream();//get the stream so we can read the image
Drawable d = Drawable.createFromStream(is, "MyBanner");//create a drawable from the image
Bitmap bmp = ((BitmapDrawable) d).getBitmap();//create a bitmap from the drawable
final Drawable dS = new BitmapDrawable(Bitmap.createScaledBitmap(bmp, 192, 192, true));//scale it to whatever size you need
con.disconnect();//disconnect now that we're done
runOnUiThread(new Runnable(){//run UI update code on the main thread
#Override
public void run() {
image1.setImageDrawable(dS);//set the imageview to the banner we downloaded
}
});
} catch (MalformedURLException e) {//catch url error
e.printStackTrace();
} catch (IOException e) {//catch io error when downloading
e.printStackTrace();
}
}
}).start();//run the thread
Change "http://your-hosting-site.com/banner.jpg" (line 6) to wherever you uploaded the .jpg, R.id.mybanner (line 1) to the id of your ImageView, and "MyBanner" (line 14) to whatever you want to call the image.
You might want to save your banner to the phone and only check after X days/hours for an update to save data, but that is up to you.
I have an Image on my server. The URL for the image is something like:
http://www.mydomain.com/123456uploaded_image.jpg
I am trying to set this image to my ImageView. Here is the code that I tried:
try{
String url1 = myeventimagearray[position];
URL ulrn = new URL(url1);
HttpURLConnection con = (HttpURLConnection)ulrn.openConnection();
InputStream is = (InputStream) con.getInputStream();
Bitmap bmp = BitmapFactory.decodeStream(is);
if (null != bmp)
iveventimg.setImageBitmap(bmp);
else
Log.i("Image","Not set");
} catch(Exception e) {
e.printStackTrace();
}
When I try this, my imageview is empty, i.e., it doesn't set the image view and i get this System err in my logcat:
java.lang.ClassCastException: libcore.net.http.FixedLengthInputStream cannot be cast to com.example.eventnotifier.Base64$InputStream
Base46.java is a file I found from the internet that Encodes and decodes to and from Base64 notation.
Any idea why I'm getting this System.error?
Thank you
Use URlImageViewHelper, it will take care of loading url into imageview.
Refer this
It will take care of caching, loading in background etc. by itself.
This is not an easy answer but you should use a caching system.
See https://github.com/chrisbanes/Android-BitmapCache for an excellent one!
Simply swap the ImageView for NetworkCacheableImageView and then use loadImage( "http://....", true );
You are likely getting an exception because you are trying to do network io on the main thread. Consider using a loader or an AsyncTask to load your image.
Check your logs, I bet you are printing a stack trace in the auto generated catch block.
new Thread(new Runnable() {
public void run() {
final Bitmap b = bitmap = BitmapFactory.decodeStream((InputStream)new URL(myeventimagearray[position]).getContent());
iveventimg.post(new Runnable() {
public void run() {
iveventimg.setImageBitmap(b);
}
});
}
}).start();
Use Picasso to fetch image from url. Implement 'com.squareup.picasso:picasso:2.71828' in build.gradle and in java
Picasso.get()
.load(url) // http://www.example.com/123456uploaded_image.jpg
.resize(50, 50)
.centerCrop()
.into(imageView)
I have a large list of objects, all of whom have a path to their image "ex. http://www.google.com/image.jpg" and I need to download the image and save the drawable to the object..
I was using AsyncTask, but even if I use my own threads I always end up with 'OutOfMemoryError' at some arbitrary point in the list. The images are never larger than 82Kb (Is this too big for android tablets?) in size, but I think the sheer number of images is causing the process as a whole to fail.
Here is what I'm currently doing.
class DownloadImageTask extends AsyncTask<ArrayList<Item>, Void, Void> {
private static int num =1;
#Override
protected Void doInBackground(ArrayList<Item>... items) {
try {
if(items.length == 0)
return null;
HttpURLConnection connection;
InputStream input;
for(ArrayList<Item> itemlist : items) {
for(Item i : itemlist) {
Log.d(JusTouchMenu.TAG,"[Item]Image request to url:"+i.getImagePath());
try {
connection = (HttpURLConnection)new URL(i.getImagePath()).openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
input = connection.getInputStream();
i.setImage(new BitmapDrawable(BitmapFactory.decodeStream(input)));//Requires a drawable
connection.disconnect();
} catch(Exception e) {Log.e(JusTouchMenu.TAG,"[Item]Unable to download image # '"+i.getImagePath()+"'",e);}
Log.v(JusTouchMenu.TAG, "[Item]Image decoded # '"+i.getImagePath()+"' #"+num++);
for(Tag pt : i.tags()) {
Log.d(JusTouchMenu.TAG,"[Item->Tag]Image request to url:"+pt.getImagePath());
try {
connection = (HttpURLConnection)new URL(pt.getImagePath()).openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
input = connection.getInputStream();
pt.setImage(new BitmapDrawable(BitmapFactory.decodeStream(input))); //Requires a drawable
connection.disconnect();
} catch(Exception e) {
Log.e(JusTouchMenu.TAG,"[Item->Tag]Unable to download image # '"+i.getImagePath()+"'",e);
}
Log.v(JusTouchMenu.TAG, "[Item->Tag]Image decoded # '"+pt.getImagePath()+"' #"+num++);
}
}
}
} catch(Exception e) {
Log.e(JusTouchMenu.TAG,"Error decoding image inside AsyncTask",e);
}
return null;
}
Thanks!
How many of these images are you trying to get at once? How are you using them?
You should probably consider using the capabilities of Gallery or GridView and thereby only be loading the images that are in view at the moment. You can even get fancy and cache them so scrolling is nice and smooth. Trying to load all of the images into an ArrayList when youre not likely to be able to display them all at once is not a mobile friendly approach.
Here are some decent references to caching approaches but you should probably get started with a basic gallery or grid view loading as needed and then add the caching on.
Lazy load of images in ListView
http://code.google.com/p/libs-for-android/wiki/ImageLoader
I've been looking everywhere to see if there is a standard way of achieving this but I find a different solution every-time.
Basically, I am trying to build a Custom ListView with an image and two-three lines of text besides it.
In order to optimize it, I understand that the following have to be used:
convertView: Basically if the view was already inflated, use it
Lazy-Loading: Do not load the content of the rows until they are called for
Background Downloading & Caching: Download images in their own threads and then update the row (and possible cache them?)
I could manage 1 and 2 but the third one is really confusing me.
Is there a best practice for this?
Thanks
Thanks to Mark for his help. This is one way of doing what he suggested (just in case some else is curious):
private class DownloadImageTask extends AsyncTask<Object, Integer, Bitmap> {
private ImageView iv;
protected Bitmap doInBackground(Object... params) {
try {
iv = (ImageView) params[0];
URL aURL = new URL("http://URLTOIMAGE/img" + params[1] + ".png" );
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Bitmap bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
return bm;
} catch (IOException e) {
return null;
}
}
protected void onPostExecute(Bitmap result) {
iv.setImageBitmap((Bitmap) result);
}
}
And it would be used as follows:
new DownloadImageTask().execute(new Object[] {ImageViewHandle, position});
Note that this is not a working code. This was taken from a larger code base so you will have to make appropriate changes to make this work.
It may be a bit early to describe something as "best practice". AsyncTask or a thread monitoring a LinkedBlockingQueue are fine ways to offload something like image fetching.
You may be interested in my ThumbnailAdapter, which handles the background downloading and caching for you.