Android Thumbnail Loading Problem - android

I'm using a thumbnail loader in my project the one mentioned below. The problem is that the it loads all the thumbnails properly except the ones who's size is of about 40K. When our back end is giving that sort of thumbnails are not generated and sometimes this eventually leads to a Crash too.
What m I supposed to do with this ?
public class ThumbnailManager
{
private final Map<String, Bitmap> drawableMap;
public static Context context;
private Resources res;
private int thumbnail_size;
public ThumbnailManager()
{
drawableMap = new HashMap<String, Bitmap >();
res = new Resources(context.getAssets(), null, null);
thumbnail_size = res.getInteger(R.ThumbnailManager.THUMBNAIL_SIZE);
}
public Bitmap fetchBitmap(String urlString)
{
if(drawableMap.containsKey(urlString))
{
return (drawableMap.get(urlString));
}
//Log.d(getClass().getSimpleName(), " Image URL :: "+ urlString);
try
{
InputStream is = fetch(urlString);
android.util.Log.v("ThumbnailManager", "ThumbnailManager " + urlString);
drawableMap.put(urlString, BitmapFactory.decodeStream(is));//Bitmap.createScaledBitmap(BitmapFactory.decodeStream(is), thumbnail_size, thumbnail_size, false));
return drawableMap.get(urlString);
}
catch(Exception e)
{
android.util.Log.v("EXCEPTION", "EXCEPTION" + urlString);
return null;
}
}
public void fetchBitmapOnThread(final String urlString, final ImageView imageView)
{
if(drawableMap.containsKey(urlString))
{
imageView.setImageBitmap(drawableMap.get(urlString));
return;
}
if(urlString.compareTo("AUDIO") == 0)
{
Bitmap audioThumb = BitmapFactory.decodeResource(context.getResources(), R.drawable.timeline_audio_thumb);
drawableMap.put(urlString, Bitmap.createScaledBitmap(audioThumb, thumbnail_size, thumbnail_size, false));
imageView.setImageBitmap(drawableMap.get(urlString));
return;
}
final Handler handler = new Handler()
{
public void handleMessage(Message message)
{
imageView.setImageBitmap((Bitmap) message.obj);
}
};
Thread thread = new Thread()
{
public void run()
{
Bitmap urlBitmap = fetchBitmap(urlString);
Message message = handler.obtainMessage(1, urlBitmap);
handler.sendMessage(message);
}
};
thread.start();
}
public InputStream fetch(String urlString) throws IOException, MalformedURLException
{
final URL url = new URL(urlString);
final URLConnection conn = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(true);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
return(conn.getInputStream());
}
}

It would be great if you added a stacktrace here. But I suspect its an memory issue too. If you are loading lots of bitmaps into memory, they require much more memory than the original filesize. Ex. your thumbnail that is 40k could be 400k as a bitmap, It depends on the resolution. Use ddms and watch how much free memory your app is steeling. If it get less then 2MB of working memory, the BitmapFactory is likly to make a RuntimeException when decoding your large thumb.

Related

Download server images to android memory card

I’m doing a android application. I need to fetch the server images and save them in a folder on the android memory card but it is not working. And do not give any error. Can anyone help me?
And does anyone know how I can browse through the image folder one by one on the server to save the images in a memory card folder.
thank you
Here is my code:
//link to access server images http://IP:8080/teste/imagens/
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new GetImages(Resources.getSystem().getString(R.string.link), "1.jpg").execute();
}
}
public class GetImages extends AsyncTask<Object, Object, Object> {
private String requestUrl, imagename_;
private Bitmap bitmap ;
private FileOutputStream fos;
protected GetImages(String requestUrl, String _imagename_) {
this.requestUrl = requestUrl;
this.imagename_ = _imagename_ ;
}
#Override
protected Object doInBackground(Object... objects) {
try {
URL url = new URL(requestUrl);
URLConnection conn = url.openConnection();
bitmap = BitmapFactory.decodeStream(conn.getInputStream());
} catch (Exception ex) {
}
return null;
}
#Override
protected void onPostExecute(Object o) {
if(!ImageStorage.checkifImageExists(imagename_))
{
ImageStorage.saveToSdCard(bitmap, imagename_);
}
}
}
public class ImageStorage {
public static String saveToSdCard(Bitmap bitmap, String filename) {
String stored = null;
File sdcard = Environment.getExternalStorageDirectory();
File folder = new File(sdcard.getAbsoluteFile(), "/imagens");
folder.mkdir();
File file = new File(folder.getAbsoluteFile(), filename + ".jpg");
if (file.exists())
return stored;
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
stored = "success";
} catch (Exception e) {
e.printStackTrace();
}
return stored;
}
public static File getImage(String imagename) {
File mediaImage = null;
try {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root);
if (!myDir.exists())
return null;
mediaImage = new File(myDir.getPath() + "/imagens/" + imagename);
} catch (Exception e) {
e.printStackTrace();
}
return mediaImage;
}
public static boolean checkifImageExists(String imagename) {
Bitmap b = null;
File file = ImageStorage.getImage("/" + imagename + ".jpg");
String path = file.getAbsolutePath();
if (path != null)
b = BitmapFactory.decodeFile(path);
if (b == null || b.equals("")) {
return false;
}
return true;
}
}
First of all avoid using AsyncTask for performing network calls. AsyncTask has vulnerabilities and can have impact on app performance and stability.
One of the most known cases is when rotation of screen happen and AsyncTask is launched.
Consider that AsyncTask is an inner class which keeps it's reference to parent class if rotation happens Activity will be re-created but your AsyncTask is still holding reference to the first created Activity and doesn't allow it to be garbage collected.
That leads to scenario known as zombie. And if result is returned to Acitivity which doesn't exist anymore, that could lead to leaks and crashes. AsyncTask should be used for internal operations like obtaining contacts from phone or similar tasks in background.
So that is why Retrofit, Volley are introduced in first place but in this scenario OkHttp is better choice so:
Download image using OkHttp:
implementation("com.squareup.okhttp3:okhttp:4.1.0")
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("put your url of image here")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.d("Failed: " + e.getMessage());
}
#Override
public void onResponse(Response response) throws IOException {
InputStream inputStream = response.body().byteStream(); // convert to inputstream
Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // get bitmap from inputstream
}
});

Image does not loaded and throwingjava.net.MalformedURLException

i am parsing a json string from which i get the url of image. then i pass that url to a method to get the image and display it in an imageview but the image does not loaded and throws an exception of java.net.MalformedURLException. when i try to pass the image url directly to the method then it gets loaded. so i dont know where is the error. Any help will be appreciated. thanks in advance. my code is below
public class CompanyDetailActivity extends Activity {
ImageView coverimage;
ImageView profileimage;
TextView fullname;
TextView tagline;
TextView industry;
TextView teamsize;
TextView about;
TextView year;
TextView location;
String Coverimage;
String Profimage;
String Fullname;
String Tagline;
String Industry;
String Teamsize;
String About;
String Year;
String Location;
// Bitmap bitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.companydetails);
coverimage = (ImageView) findViewById(R.id.CoverImage);
profileimage = (ImageView) findViewById(R.id.ProfileImage);
fullname = (TextView) findViewById(R.id.FullName);
tagline = (TextView) findViewById(R.id.TagLine);
industry = (TextView) findViewById(R.id.IndustryName);
teamsize = (TextView) findViewById(R.id.TeamSize);
about = (TextView) findViewById(R.id.CompanyAbout);
year = (TextView) findViewById(R.id.FoundYear);
location = (TextView) findViewById(R.id.Location);
new DetailsAsynTask()
.execute("http://www.mygmn.com/joblink/wp-admin/admin-ajax.php?action=joblink_searchcompanies&company_id=1180");
GetXMLTask task = new GetXMLTask();
task.execute(Coverimage);
}
public class DetailsAsynTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... arg0) {
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(arg0[0]);
HttpResponse response = client.execute(post);
int status = response.getStatusLine().getStatusCode();
if (status == 200) {
// to get response
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONObject jObj = new JSONObject(data);
JSONObject MainObject = jObj.getJSONObject("data");
CompanyDetailsModel company = new CompanyDetailsModel();
Coverimage = company.setCoverImage(MainObject
.getString("cove_img"));
Profimage = company.setCompanyProfPicture(MainObject
.getString("company_profile_picture"));
Fullname = company.setCompanyFullName(MainObject
.getString("company_full_name"));
Tagline = company.setComapnyTagLine(MainObject
.getString("company_tagline"));
Industry = company.setCompanyInustry(MainObject
.getString("company_industry"));
Teamsize = company.setCompanyTeamSize(MainObject
.getString("company_teamsize"));
About = company.setCompanyAbout(MainObject
.getString("company_about"));
Year = company.setCompanyFoundYear(MainObject
.getString("company_foundyear"));
Location = company.setCompanyLocation(MainObject
.getString("company location"));
return true;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result == false) {
} else {
fullname.setText(Fullname);
tagline.setText(Tagline);
industry.setText(Industry);
teamsize.setText(Teamsize);
about.setText(About);
year.setText(Year);
location.setText(Location);
}
}
}
private class GetXMLTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... urls) {
Bitmap map = null;
for (String url : urls) {
map = downloadImage(url);
}
return map;
}
// Sets the Bitmap returned by doInBackground
#Override
protected void onPostExecute(Bitmap result) {
coverimage.setImageBitmap(result);
}
// Creates Bitmap from InputStream and returns it
private Bitmap downloadImage(String url) {
Bitmap bitmap = null;
InputStream stream = null;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
try {
stream = getHttpConnection(url);
bitmap = BitmapFactory.decodeStream(stream, null, bmOptions);
stream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return bitmap;
}
// Makes HttpURLConnection and returns InputStream
private InputStream getHttpConnection(String urlString)
throws IOException {
InputStream stream = null;
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
try {
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
httpConnection.connect();
if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
stream = httpConnection.getInputStream();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return stream;
}
}
}
java.net.MalformedURLException can come due to security reason .you have to add http:// or https:// with your url images.
You are running two asynctasks inside onCreate() method .As these are asynchronous your GetXMLTask was executed with String CoverImage as null .
So , moving this code :
GetXMLTask task = new GetXMLTask();
task.execute(Coverimage);
to the onPostExecute() Method of your Details asynctask will solve the problem .
ok, use this code
public class ImageLoading {
public enum BitmapManager {
INSTANCE;
private final Map<String, SoftReference<Bitmap>> cache;
private final ExecutorService pool;
private Map<ImageView, String> imageViews = Collections
.synchronizedMap(new WeakHashMap<ImageView, String>());
private Bitmap placeholder;
BitmapManager() {
cache = new HashMap<String, SoftReference<Bitmap>>();
pool = Executors.newFixedThreadPool(5);
}
public void setPlaceholder(Bitmap bmp) {
placeholder = bmp;
}
public Bitmap getBitmapFromCache(String url) {
if (cache.containsKey(url)) {
return cache.get(url).get();
}
return null;
}
public void queueJob(final String url, final ImageView imageView,
final int width, final int height) {
/* Create handler in UI thread. */
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String tag = imageViews.get(imageView);
if (tag != null && tag.equals(url)) {
if (msg.obj != null) {
imageView.setImageBitmap((Bitmap) msg.obj);
} else {
imageView.setImageBitmap(placeholder);
Log.d(null, "fail " + url);
}
}
}
};
pool.submit(new Runnable() {
#Override
public void run() {
final Bitmap bmp = downloadBitmap(url, width, height);
Message message = Message.obtain();
message.obj = bmp;
Log.d(null, "Item downloaded: " + url);
handler.sendMessage(message);
}
});
}
public void loadBitmap(final String url, final ImageView imageView,
final int width, final int height) {
imageViews.put(imageView, url);
Bitmap bitmap = getBitmapFromCache(url);
// check in UI thread, so no concurrency issues
if (bitmap != null) {
Log.d(null, "Item loaded from cache: " + url);
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageBitmap(placeholder);
queueJob(url, imageView, width, height);
}
}
private Bitmap downloadBitmap(String url, int width, int height) {
try {
Bitmap bitmap = BitmapFactory.decodeStream((InputStream) new URL(
url).getContent());
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
cache.put(url, new SoftReference<Bitmap>(bitmap));
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Directly use this code,and where you are using downloading code ,use this code
ImageLoading.BitmapManager.INSTANCE.loadBitmap("http://"+image, holder.img, 150, 180);
Your URL is okay from your server response. Instead of loading the image manually try Picasso Library
with this library, you will just need to do-
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

How to download and save an image in Android

How do you download and save an image from a given url in Android?
Edit as of 30.12.2015 - The Ultimate Guide to image downloading
last major update: Mar 31 2016
TL;DR a.k.a. stop talking, just give me the code!!
Skip to the bottom of this post, copy the BasicImageDownloader (javadoc version here)
into your project, implement the OnImageLoaderListener interface
and you're done.
Note: though the BasicImageDownloader handles possible errors
and will prevent your app from crashing in case anything goes wrong, it will not perform
any post-processing (e.g. downsizing) on the downloaded Bitmaps.
Since this post has received quite a lot of attention, I have decided to completely rework it to prevent the folks from using deprecated technologies, bad programming practices or just doing silly things - like looking for "hacks" to run network on the main thread or accept all SSL certs.
I've created a demo project named "Image Downloader" that demonstrates how to download (and save) an image using my own downloader implementation, the Android's built-in DownloadManager as well as some popular open-source libraries. You can view the complete source code or download the project on GitHub.
Note: I have not adjusted the permission management for SDK 23+ (Marshmallow) yet, thus the project is targeting SDK 22 (Lollipop).
In my conclusion at the end of this post I will share my humble opinion about the proper use-case for each particular way of image downloading I've mentioned.
Let's start with an own implementation (you can find the code at the end of the post). First of all, this is a BasicImageDownloader and that's it. All it does is connecting to the given url, reading the data and trying to decode it as a Bitmap, triggering the OnImageLoaderListener interface callbacks when appropriate.
The advantage of this approach - it is simple and you have a clear overview of what's going on. A good way to go if all you need is downloading/displaying and saving some images, whilst you don't care about maintaining a memory/disk cache.
Note: in case of large images, you might need to scale them
down.
--
Android DownloadManager is a way to let the system handle the download for you. It's actually capable of downloading any kind of files, not just images. You may let your download happen silently and invisible to the user, or you can enable the user to see the download in the notification area. You can also register a BroadcastReceiver to get notified after you download is complete. The setup is pretty much straightforward, refer to the linked project for sample code.
Using the DownloadManager is generally not a good idea if you also want to display the image, since you'd need to read and decode the saved file instead of just setting the downloaded Bitmap into an ImageView. The DownloadManager also does not provide any API for you app to track the download progress.
--
Now the introduction of the great stuff - the libraries. They can do much more than just downloading and displaying images, including: creating and managing the memory/disk cache, resizing images, transforming them and more.
I will start with Volley, a powerful library created by Google and covered by the official documentation. While being a general-purpose networking library not specializing on images, Volley features quite a powerful API for managing images.
You will need to implement a Singleton class for managing Volley requests and you are good to go.
You might want to replace your ImageView with Volley's NetworkImageView, so the download basically becomes a one-liner:
((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());
If you need more control, this is what it looks like to create an ImageRequest with Volley:
ImageRequest imgRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap response) {
//do stuff
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888,
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//do stuff
}
});
It is worth mentioning that Volley features an excellent error handling mechanism by providing the VolleyError class that helps you to determine the exact cause of an error. If your app does a lot of networking and managing images isn't its main purpose, then Volley it a perfect fit for you.
--
Square's Picasso is a well-known library which will do all of the image loading stuff for you. Just displaying an image using Picasso is as simple as:
Picasso.with(myContext)
.load(url)
.into(myImageView);
By default, Picasso manages the disk/memory cache so you don't need to worry about that. For more control you can implement the Target interface and use it to load your image into - this will provide callbacks similar to the Volley example. Check the demo project for examples.
Picasso also lets you apply transformations to the downloaded image and there are even other libraries around that extend those API. Also works very well in a RecyclerView/ListView/GridView.
--
Universal Image Loader is an another very popular library serving the purpose of image management. It uses its own ImageLoader that (once initialized) has a global instance which can be used to download images in a single line of code:
ImageLoader.getInstance().displayImage(url, myImageView);
If you want to track the download progress or access the downloaded Bitmap:
ImageLoader.getInstance().displayImage(url, myImageView, opts,
new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
//do stuff
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
//do stuff
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
//do stuff
}
#Override
public void onLoadingCancelled(String imageUri, View view) {
//do stuff
}
}, new ImageLoadingProgressListener() {
#Override
public void onProgressUpdate(String imageUri, View view, int current, int total) {
//do stuff
}
});
The opts argument in this example is a DisplayImageOptions object. Refer to the demo project to learn more.
Similar to Volley, UIL provides the FailReason class that enables you to check what went wrong on download failure. By default, UIL maintains a memory/disk cache if you don't explicitly tell it not to do so.
Note: the author has mentioned that he is no longer maintaining the project as of Nov 27th, 2015. But since there are many contributors, we can hope that the Universal Image Loader will live on.
--
Facebook's Fresco is the newest and (IMO) the most advanced library that takes image management to a new level: from keeping Bitmaps off the java heap (prior to Lollipop) to supporting animated formats and progressive JPEG streaming.
To learn more about ideas and techniques behind Fresco, refer to this post.
The basic usage is quite simple. Note that you'll need to call Fresco.initialize(Context); only once, preferable in the Application class. Initializing Fresco more than once may lead to unpredictable behavior and OOM errors.
Fresco uses Drawees to display images, you can think of them as of ImageViews:
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/drawee"
android:layout_width="match_parent"
android:layout_height="match_parent"
fresco:fadeDuration="500"
fresco:actualImageScaleType="centerCrop"
fresco:placeholderImage="#drawable/placeholder_grey"
fresco:failureImage="#drawable/error_orange"
fresco:placeholderImageScaleType="fitCenter"
fresco:failureImageScaleType="centerInside"
fresco:retryImageScaleType="centerCrop"
fresco:progressBarImageScaleType="centerInside"
fresco:progressBarAutoRotateInterval="1000"
fresco:roundAsCircle="false" />
As you can see, a lot of stuff (including transformation options) gets already defined in XML, so all you need to do to display an image is a one-liner:
mDrawee.setImageURI(Uri.parse(url));
Fresco provides an extended customization API, which, under circumstances, can be quite complex and requires the user to read the docs carefully (yes, sometimes you need to RTFM).
I have included examples for progressive JPEG's and animated images into the sample project.
Conclusion - "I have learned about the great stuff, what should I use now?"
Note that the following text reflects my personal opinion and should
not be taken as a postulate.
If you only need to download/save/display some images, don't plan to use them in a Recycler-/Grid-/ListView and don't need a whole bunch of images to be display-ready, the BasicImageDownloader should fit your needs.
If your app saves images (or other files) as a result of a user or an automated action and you don't need the images to be displayed often, use the Android DownloadManager.
In case your app does a lot of networking, transmits/receives JSON data, works with images, but those are not the main purpose of the app, go with Volley.
Your app is image/media-focused, you'd like to apply some transformations to images and don't want to bother with complex API: use Picasso (Note: does not provide any API to track the intermediate download status) or Universal Image Loader
If your app is all about images, you need advanced features like displaying animated formats and you are ready to read the docs, go with Fresco.
In case you missed that, the Github link for the demo project.
And here's the BasicImageDownloader.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Set;
public class BasicImageDownloader {
private OnImageLoaderListener mImageLoaderListener;
private Set<String> mUrlsInProgress = new HashSet<>();
private final String TAG = this.getClass().getSimpleName();
public BasicImageDownloader(#NonNull OnImageLoaderListener listener) {
this.mImageLoaderListener = listener;
}
public interface OnImageLoaderListener {
void onError(ImageError error);
void onProgressChange(int percent);
void onComplete(Bitmap result);
}
public void download(#NonNull final String imageUrl, final boolean displayProgress) {
if (mUrlsInProgress.contains(imageUrl)) {
Log.w(TAG, "a download for this url is already running, " +
"no further download will be started");
return;
}
new AsyncTask<Void, Integer, Bitmap>() {
private ImageError error;
#Override
protected void onPreExecute() {
mUrlsInProgress.add(imageUrl);
Log.d(TAG, "starting download");
}
#Override
protected void onCancelled() {
mUrlsInProgress.remove(imageUrl);
mImageLoaderListener.onError(error);
}
#Override
protected void onProgressUpdate(Integer... values) {
mImageLoaderListener.onProgressChange(values[0]);
}
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = null;
HttpURLConnection connection = null;
InputStream is = null;
ByteArrayOutputStream out = null;
try {
connection = (HttpURLConnection) new URL(imageUrl).openConnection();
if (displayProgress) {
connection.connect();
final int length = connection.getContentLength();
if (length <= 0) {
error = new ImageError("Invalid content length. The URL is probably not pointing to a file")
.setErrorCode(ImageError.ERROR_INVALID_FILE);
this.cancel(true);
}
is = new BufferedInputStream(connection.getInputStream(), 8192);
out = new ByteArrayOutputStream();
byte bytes[] = new byte[8192];
int count;
long read = 0;
while ((count = is.read(bytes)) != -1) {
read += count;
out.write(bytes, 0, count);
publishProgress((int) ((read * 100) / length));
}
bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
} else {
is = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
}
} catch (Throwable e) {
if (!this.isCancelled()) {
error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
this.cancel(true);
}
} finally {
try {
if (connection != null)
connection.disconnect();
if (out != null) {
out.flush();
out.close();
}
if (is != null)
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
if (result == null) {
Log.e(TAG, "factory returned a null result");
mImageLoaderListener.onError(new ImageError("downloaded file could not be decoded as bitmap")
.setErrorCode(ImageError.ERROR_DECODE_FAILED));
} else {
Log.d(TAG, "download complete, " + result.getByteCount() +
" bytes transferred");
mImageLoaderListener.onComplete(result);
}
mUrlsInProgress.remove(imageUrl);
System.gc();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public interface OnBitmapSaveListener {
void onBitmapSaved();
void onBitmapSaveError(ImageError error);
}
public static void writeToDisk(#NonNull final File imageFile, #NonNull final Bitmap image,
#NonNull final OnBitmapSaveListener listener,
#NonNull final Bitmap.CompressFormat format, boolean shouldOverwrite) {
if (imageFile.isDirectory()) {
listener.onBitmapSaveError(new ImageError("the specified path points to a directory, " +
"should be a file").setErrorCode(ImageError.ERROR_IS_DIRECTORY));
return;
}
if (imageFile.exists()) {
if (!shouldOverwrite) {
listener.onBitmapSaveError(new ImageError("file already exists, " +
"write operation cancelled").setErrorCode(ImageError.ERROR_FILE_EXISTS));
return;
} else if (!imageFile.delete()) {
listener.onBitmapSaveError(new ImageError("could not delete existing file, " +
"most likely the write permission was denied")
.setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
return;
}
}
File parent = imageFile.getParentFile();
if (!parent.exists() && !parent.mkdirs()) {
listener.onBitmapSaveError(new ImageError("could not create parent directory")
.setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
return;
}
try {
if (!imageFile.createNewFile()) {
listener.onBitmapSaveError(new ImageError("could not create file")
.setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
return;
}
} catch (IOException e) {
listener.onBitmapSaveError(new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION));
return;
}
new AsyncTask<Void, Void, Void>() {
private ImageError error;
#Override
protected Void doInBackground(Void... params) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(imageFile);
image.compress(format, 100, fos);
} catch (IOException e) {
error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
this.cancel(true);
} finally {
if (fos != null) {
try {
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onCancelled() {
listener.onBitmapSaveError(error);
}
#Override
protected void onPostExecute(Void result) {
listener.onBitmapSaved();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public static Bitmap readFromDisk(#NonNull File imageFile) {
if (!imageFile.exists() || imageFile.isDirectory()) return null;
return BitmapFactory.decodeFile(imageFile.getAbsolutePath());
}
public interface OnImageReadListener {
void onImageRead(Bitmap bitmap);
void onReadFailed();
}
public static void readFromDiskAsync(#NonNull File imageFile, #NonNull final OnImageReadListener listener) {
new AsyncTask<String, Void, Bitmap>() {
#Override
protected Bitmap doInBackground(String... params) {
return BitmapFactory.decodeFile(params[0]);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (bitmap != null)
listener.onImageRead(bitmap);
else
listener.onReadFailed();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imageFile.getAbsolutePath());
}
public static final class ImageError extends Throwable {
private int errorCode;
public static final int ERROR_GENERAL_EXCEPTION = -1;
public static final int ERROR_INVALID_FILE = 0;
public static final int ERROR_DECODE_FAILED = 1;
public static final int ERROR_FILE_EXISTS = 2;
public static final int ERROR_PERMISSION_DENIED = 3;
public static final int ERROR_IS_DIRECTORY = 4;
public ImageError(#NonNull String message) {
super(message);
}
public ImageError(#NonNull Throwable error) {
super(error.getMessage(), error.getCause());
this.setStackTrace(error.getStackTrace());
}
public ImageError setErrorCode(int code) {
this.errorCode = code;
return this;
}
public int getErrorCode() {
return errorCode;
}
}
}
I have just came from solving this problem on and I would like to share the complete code that can download, save to the SD Card (and hide the filename) and retrieve the images and finally it checks if the image is already there. The url comes from the database so the filename can be uniquely easily using id.
First, create a class for Downloading Images.
private class GetImages extends AsyncTask<Object, Object, Object> {
private String requestUrl, imagename_;
private ImageView view;
private Bitmap bitmap;
private FileOutputStream fos;
private GetImages(String requestUrl, ImageView view, String _imagename_) {
this.requestUrl = requestUrl;
this.view = view;
this.imagename_ = _imagename_;
}
#Override
protected Object doInBackground(Object... objects) {
try {
URL url = new URL(requestUrl);
URLConnection conn = url.openConnection();
bitmap = BitmapFactory.decodeStream(conn.getInputStream());
} catch (Exception ex) {
}
return null;
}
#Override
protected void onPostExecute(Object o) {
if (!ImageStorage.checkifImageExists(imagename_)) {
view.setImageBitmap(bitmap);
ImageStorage.saveToSdCard(bitmap, imagename_);
}
}
}
Then, create a class for saving and retrieving the files.
public class ImageStorage {
public static String saveToSdCard(Bitmap bitmap, String filename) {
String stored = null;
File sdcard = Environment.getExternalStorageDirectory();
File folder = new File(sdcard.getAbsoluteFile(), ".your_specific_directory");//the dot makes this directory hidden to the user
folder.mkdir();
File file = new File(folder.getAbsoluteFile(), filename + ".jpg");
if (file.exists())
return stored;
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
stored = "success";
} catch (Exception e) {
e.printStackTrace();
}
return stored;
}
public static File getImage(String imagename) {
File mediaImage = null;
try {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root);
if (!myDir.exists())
return null;
mediaImage = new File(myDir.getPath() + "/.your_specific_directory/" + imagename);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mediaImage;
}
public static boolean checkifImageExists(String imagename) {
Bitmap b = null;
File file = ImageStorage.getImage("/" + imagename + ".jpg");
String path = file.getAbsolutePath();
if (path != null)
b = BitmapFactory.decodeFile(path);
if (b == null || b.equals("")) {
return false;
}
return true;
}
}
Then, to access the images first check if it is already there; if not then download.
if(ImageStorage.checkifImageExists(imagename)) {
File file = ImageStorage.getImage("/"+imagename+".jpg");
String path = file.getAbsolutePath();
if (path != null){
b = BitmapFactory.decodeFile(path);
imageView.setImageBitmap(b);
}
} else {
new GetImages(imgurl, imageView, imagename).execute() ;
}
This code might help you.
Button download_image = (Button) bigimagedialog.findViewById(R.id.btn_downloadimage);
download_image.setOnClickListener(new View.OnClickListener()
{
public void onClick (View v)
{
boolean success = (new File("/sdcard/dirname")).mkdir();
if (!success) {
Log.w("directory not created", "directory not created");
}
try {
URL url = new URL("YOUR_URL");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
String data1 = String.valueOf(String.format("/sdcard/dirname/%d.jpg", System.currentTimeMillis()));
FileOutputStream stream = new FileOutputStream(data1);
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outstream);
byte[] byteArray = outstream.toByteArray();
stream.write(byteArray);
stream.close();
Toast.makeText(getApplicationContext(), "Downloading Completed", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
I have a simple solution which is working perfectly. The code is not mine, I found it on this link. Here are the steps to follow:
1. Before downloading the image, let’s write a method for saving bitmap into an image file in the internal storage in android. It needs a context, better to use the pass in the application context by getApplicationContext(). This method can be dumped into your Activity class or other util classes.
public void saveImage(Context context, Bitmap b, String imageName)
{
FileOutputStream foStream;
try
{
foStream = context.openFileOutput(imageName, Context.MODE_PRIVATE);
b.compress(Bitmap.CompressFormat.PNG, 100, foStream);
foStream.close();
}
catch (Exception e)
{
Log.d("saveImage", "Exception 2, Something went wrong!");
e.printStackTrace();
}
}
2. Now we have a method to save bitmap into an image file in andorid, let’s write the AsyncTask for downloading images by url. This private class need to be placed in your Activity class as a subclass. After the image is downloaded, in the onPostExecute method, it calls the saveImage method defined above to save the image. Note, the image name is hardcoded as “my_image.png”.
private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
private String TAG = "DownloadImage";
private Bitmap downloadImageBitmap(String sUrl) {
Bitmap bitmap = null;
try {
InputStream inputStream = new URL(sUrl).openStream(); // Download Image from URL
bitmap = BitmapFactory.decodeStream(inputStream); // Decode Bitmap
inputStream.close();
} catch (Exception e) {
Log.d(TAG, "Exception 1, Something went wrong!");
e.printStackTrace();
}
return bitmap;
}
#Override
protected Bitmap doInBackground(String... params) {
return downloadImageBitmap(params[0]);
}
protected void onPostExecute(Bitmap result) {
saveImage(getApplicationContext(), result, "my_image.png");
}
}
3. The AsyncTask for downloading the image is defined, but we need to execute it in order to run that AsyncTask. To do so, write this line in your onCreate method in your Activity class, or in an onClick method of a button or other places you see fit.
new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");
The image should be saved in /data/data/your.app.packagename/files/my_image.jpeg, check this post for accessing this directory from your device.
IMO this solves the issue! If you want further steps such as load the image you can follow these extra steps:
4. After the image is downloaded, we need a way to load the image bitmap from the internal storage, so we can use it. Let’s write the method for loading the image bitmap. This method takes two paramethers, a context and an image file name, without the full path, the context.openFileInput(imageName) will look up the file at the save directory when this file name was saved in the above saveImage method.
public Bitmap loadImageBitmap(Context context, String imageName) {
Bitmap bitmap = null;
FileInputStream fiStream;
try {
fiStream = context.openFileInput(imageName);
bitmap = BitmapFactory.decodeStream(fiStream);
fiStream.close();
} catch (Exception e) {
Log.d("saveImage", "Exception 3, Something went wrong!");
e.printStackTrace();
}
return bitmap;
}
5. Now we have everything we needed for setting the image of an ImageView or any other Views that you like to use the image on. When we save the image, we hardcoded the image name as “my_image.jpeg”, now we can pass this image name to the above loadImageBitmap method to get the bitmap and set it to an ImageView.
someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));
6. To get the image full path by image name.
File file = getApplicationContext().getFileStreamPath("my_image.jpeg");
String imageFullPath = file.getAbsolutePath();
7. Check if the image file exists.
File file =
getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
To delete the image file.
File file = getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.delete()) Log.d("file", "my_image.jpeg deleted!");
Code for download image in android studio:
DownloadManager downloadManager =
(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setNotificationVisibility
(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadManager.enqueue(request);
FancyToast.makeText(getApplicationContext(), "Downloaded",
FancyToast.LENGTH_SHORT, FancyToast.SUCCESS, false).show();
this code perfectly run in my project
downloadImagesToSdCard(imagepath,imagepath);
private void downloadImagesToSdCard(String downloadUrl,String imageName)
{
try
{
URL url = new URL("www.xxx.com"+downloadUrl);
/* making a directory in sdcard */
// String sdCard=Environment.getExternalStorageDirectory().toString();
ContextWrapper cw = new ContextWrapper(getActivity());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("files", Context.MODE_PRIVATE);
File myDir = new File(directory,"folder");
/* if specified not exist create new */
if(!myDir.exists())
{
myDir.mkdir();
Log.v("", "inside mkdir");
}
/* checks the file and if it already exist delete */
String fname = imageName;
File file = new File (myDir, fname);
Log.d("file===========path", ""+file);
if (file.exists ())
file.delete ();
/* Open a connection */
URLConnection ucon = url.openConnection();
InputStream inputStream = null;
HttpURLConnection httpConn = (HttpURLConnection)ucon;
httpConn.setRequestMethod("GET");
httpConn.connect();
inputStream = httpConn.getInputStream();
/*if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
{
inputStream = httpConn.getInputStream();
}*/
FileOutputStream fos = new FileOutputStream(file);
int totalSize = httpConn.getContentLength();
int downloadedSize = 0;
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ( (bufferLength = inputStream.read(buffer)) >0 )
{
fos.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
Log.i("Progress:","downloadedSize:"+downloadedSize+"totalSize:"+ totalSize) ;
}
fos.close();
Log.d("test", "Image Saved in sdcard..");
viewimage();
}
catch(IOException io)
{
io.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void viewimage()
{
String path = serialnumber+".png";
ContextWrapper cw = new ContextWrapper(getActivity());
//path to /data/data/yourapp/app_data/dirName
File directory = cw.getDir("files", Context.MODE_PRIVATE);
File mypath=new File(directory,"folder/"+path);
Bitmap b;
try {
b = BitmapFactory.decodeStream(new FileInputStream(mypath));
// b.compress(format, quality, stream)
profile_image.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Try this
try
{
Bitmap bmp = null;
URL url = new URL("Your_URL");
URLConnection conn = url.openConnection();
bmp = BitmapFactory.decodeStream(conn.getInputStream());
File f = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis() + ".jpg");
if(f.exists())
f.delete();
f.createNewFile();
Bitmap bitmap = bmp;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();
Log.e(TAG, "imagepath: "+f );
}
catch (Exception e)
{
e.printStackTrace();
}
public class testCrop extends AppCompatActivity {
ImageView iv;
String imagePath = "https://style.pk/wp-content/uploads/2015/07/omer-Shahzad-performed-umrah-600x548.jpg";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.testcrpop);
iv = (ImageView) findViewById(R.id.testCrop);
imageDownload image = new imageDownload(testCrop.this, iv);
image.execute(imagePath);
}
class imageDownload extends AsyncTask<String, Integer, Bitmap> {
Context context;
ImageView imageView;
Bitmap bitmap;
InputStream in = null;
int responseCode = -1;
//constructor.
public imageDownload(Context context, ImageView imageView) {
this.context = context;
this.imageView = imageView;
}
#Override
protected void onPreExecute() {
}
#Override
protected Bitmap doInBackground(String... params) {
try {
URL url = new URL(params[0]);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.connect();
responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
in = httpURLConnection.getInputStream();
bitmap = BitmapFactory.decodeStream(in);
in.close();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap data) {
imageView.setImageBitmap(data);
saveImage(data);
}
private void saveImage(Bitmap data) {
File createFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"test");
createFolder.mkdir();
File saveImage = new File(createFolder,"downloadimage.jpg");
try {
OutputStream outputStream = new FileOutputStream(saveImage);
data.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
OUTPUT
Make sure you added permission to write data in memory
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
#Droidman post is pretty comprehensive. Volley works good with small data of few kbytes. When I tried to use the 'BasicImageDownloader.java' the Android Studio gave me warning that the AsyncTask class should to be static or there could be leaks. I used Volley in another test app and that kept crashing because of leaks so I am worried about using Volley for the image downloader (images can be few 100 kB).
I used Picasso and it worked well, there is small change (probably an update on Picasso) from what is posted above. Below code worked for me:
public static void imageDownload(Context ctx, String url){
Picasso.get().load(yourURL)
.into(getTarget(url));
}
private static Target getTarget(final String url){
Target target2 = new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
File file = new File(localPath + "/"+"YourImageFile.jpg");
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.flush();
ostream.close();
} catch (IOException e) {
Log.e("IOException", e.getLocalizedMessage());
}
}
}).start();
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
return target;
}
As Google tells, for now, don't forget to add also readable on external storage in the manifest :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Source : http://developer.android.com/training/basics/data-storage/files.html#GetWritePermission

Bitmaps Taking To Much Memory

I'm getting an error saying that the Bitmaps are using to much memory.
I know that I should use bitmap.recyle() but I don't know where to put it, wherever I put it I get an error saying that I'm trying to use a recycled bitmap.
If anyone can help that would be great.
Here is my relevant code:
public class PictureViewer extends SherlockActivity implements
android.view.GestureDetector.OnGestureListener {
private ViewFlipper viewFlipper = null;
private GestureDetector gestureDetector = null;
ArrayList<Integer> number = new ArrayList<Integer>();
DownloadBitmap bit = new DownloadBitmap();
int j = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.pictureviewer);
viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
gestureDetector = new GestureDetector(this);
for (int i = 1; i <= 65; ++i)
number.add(i);
Collections.shuffle(number);
loadImage();
loadImage();
}
public void loadImage() {
if (j == 65) { // Change this number to exact ammount of pictures
j = 1;
}
int next = number.get(j);
j++;
ImageView image = new ImageView(this);
Bitmap bitmap = bit.createBitmapFromUrl("http://comedyzone.mobi/img" + next + ".jpg");
WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
image.setImageBitmap(mBitmapReference.get());
image.setScaleType(ImageView.ScaleType.FIT_XY);
viewFlipper.addView(image, new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
}
#Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
if (arg0.getX() - arg1.getX() > 120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
this.viewFlipper.showNext();
loadImage();
return true;
} else if (arg0.getX() - arg1.getX() < -120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_out));
this.viewFlipper.showPrevious();
loadImage();
return true;
}
return true;
}
#Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return this.gestureDetector.onTouchEvent(event);
}
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
throw new IOException("Error connecting");
}
return in;
}
I know that I should use bitmap.recyle()
Calling recycle is not necessary.
Last year at Google IO, there was a talk given precisely on this topic.
Google I/O 2011: Memory management for Android Apps - You should definitely watch all of this, it's worth the time.
Making a WeakReference to your Bitmap object is a good start towards better Bitmap management. For example:
Bitmap bitmap = DownloadImage("http://comedyzone.mobi/img" + next + ".jpg");
WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
image.setImageBitmap(mBitmapReference.get());
Displaying Bitmaps Efficiently
These are Android training classes you should read through too.
Also, this is a class I wrote to download an image from a URL. You should consider using it in place of your DownloadImage method, it's much more efficient.
DownloadBitmap
public class DownloadBitmap {
private static String LOG_TAG = DownloadBitmap.class.getName();
/**
* #param url
* #return Bitmap image from the interwebs
*/
static Bitmap createBitmapFromUrl(String url) {
final Bitmap mBitmap = readBitmapFromNetwork(url);
final WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(mBitmap);
if (mBitmapReference.get() != null)
return mBitmapReference.get();
return null;
}
/**
* #param urlString The URL to read the bitmap from.
* #return A Bitmap image or null if an error occurs.
*/
private static Bitmap readBitmapFromNetwork(String urlString) {
InputStream mInputStream = null;
FlushedInputStream mFlushedInputStream = null;
Bitmap mBitmap = null;
WeakReference<Bitmap> mBitmapReference = null;
try {
final BitmapFactory.Options mOptions = new BitmapFactory.Options();
mOptions.inPurgeable = true;
mOptions.inDither = false;
final URL mUrl = new URL(urlString);
final URLConnection mConnection = mUrl.openConnection();
mConnection.connect();
mInputStream = mConnection.getInputStream();
mFlushedInputStream = new FlushedInputStream(mInputStream);
mBitmap = BitmapFactory.decodeStream(mFlushedInputStream, null, mOptions);
mBitmapReference = new WeakReference<Bitmap>(mBitmap);
} catch (MalformedURLException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Bad image URL", e);
return null;
} catch (IOException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Could not get remote image", e);
return null;
} finally {
try {
if (mInputStream != null)
mInputStream.close();
if (mFlushedInputStream != null)
mFlushedInputStream.close();
} catch (IOException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Error closing stream.");
return null;
}
}
if (mBitmapReference.get() != null)
return mBitmapReference.get();
return null;
}
/**
* An InputStream that skips the exact number of bytes provided, unless it
* reaches EOF.
*/
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
#Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int bytes = read();
if (bytes < 0) {
break;
} else {
bytesSkipped = 1;
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}
You need to reduce the sample size of the bitmap before using it. This can be used to do so.
private Bitmap decodeFile(File file)
{
try
{
//********************* decode image size ********************
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file), null, options);
// ********************** Find the correct scale value. It should be the power of 2. ********************
options.inSampleSize = BitmapConverter.calculateInSampleSize(options, 145, 105);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(new FileInputStream(file), null, options);
}
catch(FileNotFoundException eFileNotFoundException)
{
return null;
}
}
And then you can call Bitmap.recycle() if required, although I feel that it wouldn't be necessary.
ImageLoader
You can use Imageloader class which load your images in background.
Imageloader
You can write bitmap.recycle() just after this statement image.setImageBitmap(bitmap); which is in loadImage() function, since bitmap is no longer required after this statement.
This error occurs because either you have used a bitmap which is of very large size, or you have a memory leak in your code.
Whenever you are using a bitmap, always try to use all possible Options to use as minimum memory as possible.
For more info please see my answer on same issue.
Generally speaking you should mark an object for clean up when it's no longer needed. In your situation the only time I see you won't be needing these bitmaps any longer is when the activity is no longer at the front.
What I do see is the potential for unnecessarily large bitmaps being used with your ViewFlipper. You should resize the bitmap before setting them inside of an ImageView rather than resizing the ImageView after adding them. Try using inSampleSize as an option with BitmapFactory and resize the bitmap with Bitmap.createScaledBitmap() before loading it into a ImageView.

Multiple imageView refreshing in Android using asynctasks?

what I have to do is to play videos on a single activity, the number of videos is undefined, could be from 1 to 8, a video in my case is an image sequence, where every image is downloaded from a cam on the internet using a fixed time interl.
Do a single video activity is not a problem, I can make it using ImageView and a AsyncTask, using many instances of this method when I try to make multiple videos activities does not work, only one of the video plays. I don't know exactly what it happens but I think it could be a cuncurrency related issue due to the UIThread.
Here the used AsyncTask code:
private class AsyncTask_LiveView extends AsyncTask<String, Integer, Void>
{
private String sImageMessage = "";
private final WeakReference<ImageView> imageViewReference;
private Bitmap bmImage = null;
private String url = "";
private String usr = "";
private String pwd = "";
private utils u = new utils();
public AsyncTask_LiveView(ImageView imageView, String Url, String Usr, String Pwd)
{
imageViewReference = new WeakReference<ImageView>(imageView);
url = Url;
usr = Usr;
pwd = Pwd;
}
// automatically done on worker thread (separate from UI thread)
#Override
protected Void doInBackground(final String... args)
{
while(!isCancelled())
{
if(isCancelled())
return null;
SystemClock.sleep(200);
Log.v("ImageDownload","test");
bmImage = u.DownloadBitmapFromUrl(url, usr, pwd);
publishProgress(0);
}
return null;
}
// can use UI thread here
#Override
public void onProgressUpdate(Integer... i)
{
Log.v("Image", "Setup Image");
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bmImage);
}
}
}
}
I start the AsyncTasks in this way:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layoutliveviewdouble);
this.imgV1 = (ImageView ) findViewById(R.id.imageView1);
aTaskImgV1 = new AsyncTask_LiveView(imgV1,
URL1,
"",
"");
this.imgV2 = (ImageView ) findViewById(R.id.imageView2);
aTaskImgV2 = new AsyncTask_LiveView(imgV2,
URL2,
"root",
"jenimex123");
aTaskImgV1.execute();
aTaskImgV2.execute();
}
The DownloadBitmapFromUrl method is:
public Bitmap DownloadBitmapFromUrl(String imageURL, final String usr, final String pwd) { //this is the downloader method
try {
URL url = new URL(imageURL);
/* Open a connection to that URL. */
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
ucon.setRequestMethod("GET");
ucon.setDoOutput(true);
Authenticator.setDefault (new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication (usr, pwd.toCharArray());
}
});
ucon.connect();
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
/*
* Read bytes to the Buffer until there is nothing more to read(-1).
*/
ByteArrayBuffer baf = new ByteArrayBuffer(100000);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
/* Convert the Bytes read to a String. */
Bitmap bmp = BitmapFactory.decodeByteArray(baf.toByteArray(), 0, baf.length());
return bmp;
} catch (Exception e) {
//Log.d("ImageManager", "Error: " + e);
return null;
}
}
Any Ideas?
Solution : (21/01/11)
The bounch of lines:
Authenticator.setDefault (new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication (usr, pwd.toCharArray());
}
});
were braking the mechanism. In fact only one credentials pair a could have been set globally, and the other download processes stucked in requesting using the wrong credentials.
The solution is:
String authString = usr + ":" + pwd;
byte[] authEncBytes = Base64.encode(authString.getBytes(), Base64.DEFAULT);
String authStringEnc = new String(authEncBytes);
ucon = (HttpURLConnection) url.openConnection();
if(_usr != "")
ucon.setRequestProperty("Authorization", "Basic " + authStringEnc);
Thanks to all.
I think yuo should use unique AsyncTask_LiveView for each ImageView.
Does this function support multiple threads?
bmImage = u.DownloadBitmapFromUrl(url, usr, pwd);
It looks like some of the methods you call in downloadBitmapFromUrl(..) method involve synchronization by some common object. Try adding some extra logging to each part of this method and see where each thread gets stuck. I would do it this way:
public Bitmap downloadBitmapFromUrl(String imageURL, final String usr, final String pwd) { //this is the downloader method
try {
...
Log.i(toString() + " in " + Thread.currentThread(), "is about to open connection...");
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
Log.i(toString() + " in " + Thread.currentThread(), "has opened connection");
...
and so on.

Categories

Resources