How to recycle a bitmap in a AsyncTask? Android - android

I am writing a small android application that uses an asyncTask to display an image from a web service. The code works but it has been brought to my attention that I should recycle this bitmap.
My question is, is there a way to recycle this bitmap after I am done using it?
I attempted a solution using the onStop() and either the bitmap didn't get recycled or the image wouldn't display at all.
Here is my OnCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Other unrelated things
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
imageUrl = bundle.getString("imageUrl");
displayImage();
}
And here is my AsyncTask
private void displayImage() {
new AsyncTask<String, Void, Bitmap>() {
protected Bitmap doInBackground(String... params) {
try {
return loadBitmap(params[0]);
} catch (Exception e) {
Logger.e(TAG, getString(R.string.error_loading_image_bitmap));
return null;
}
}
protected Bitmap loadBitmap(String urlSpec) throws IOException {
InputStream is = new URL(urlSpec).openStream();
try {
return BitmapFactory.decodeStream(is);
} finally {
is.close();
}
}
protected void onPostExecute(Bitmap bitmap) {
if (bitmap != null) {
ImageView invoiceItemImageView = (ImageView) findViewById(R.id.some_id_here);
invoiceItemImageView.setImageBitmap(bitmap);
}
}
}.execute(imageUrl);
}

Override method View.onDetachedFromWindow() and recycle your Bitmap there.

Related

Android AsyncTask, how to get the result back?

I need to load an image from the web in my app, I found a good example here, but I can't figure out how to use the returned Bitmap in my Main Activity :
the class :
public class GetImageFromServer extends AsyncTask<Void, Void, Bitmap {
private String sURL;
GetImageFromServer(String urlParam) {
sURL = urlParam;
}
#Override
protected Bitmap doInBackground(Void... urlParam) {
Bitmap bmp = null;
//ImageView img = (ImageView) findViewById(R.id.imageView1);
try {
URL url = new URL(sURL);
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (Exception ex) {
Log.println(1, "Profile:getImg", ex.getMessage());
}
return bmp;
}
#Override
protected void onPreExecute() {}
}
And the MainActivity code :
String urlImage = "http://www.xxxxxx.com/css/images/xxxxxx.png";
GetImageFromServer gifs = new GetImageFromServer(urlImage);
gifs.execute();
if(person.has("Avatar")) {Avatar.setImageBitmap( gifs.execute())}
The error is :
gifs.execute()
Thanks for your help !
Add :
I added this "cancel(true)" because I have connection problems to JSON webservices after severals start/debug/close, but I doesn't seem to work :
#Override
protected Bitmap doInBackground(String... urlParam) {
if (isCancelled())
this.cancel(true);
Bitmap b = null;........
and
#Override
protected void onPostExecute(Bitmap result) {
// use the result
mImageView.setImageBitmap(result);
this.cancel(true);
}
Could the assynctasks prevent my app to connect to my webservices ?
There is a good library for doing async image loadings, here is a link: https://github.com/square/picasso.
Or you could follow this approach:
public class LoadImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
private ImageView mImageView;
public LoadImageAsyncTask(ImageView imageView) {
mImageView = imageView;
}
#Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
try {
URL url = new URL(params[0]);
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (Exception ex) {
Log.println(1, "Profile:getImg", ex.getMessage());
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}
In your activity call:
LoadImageAsyncTask task = new LoadImageAsyncTask(findViewById(R.id.yourImageId)).execute(stringUrl);
you have to implement a callback
your asynctask
public class GetImageFromServer extends AsyncTask<Void, Void, Bitmap> {
private String sURL;
private Bitmap b;
YourCallback mOwner;
GetImageFromServer(YourCallback owner, String urlParam) {
sURL = urlParam;
mOwner = owner;
}
#Override
protected Bitmap doInBackground(Void... urlParam) {
try {
URL url = new URL(sURL);
b = BitmapFactory.decodeStream(url.openConnection()
.getInputStream());
} catch (Exception ex) {
Log.println(1, "Profile:getImg", ex.getMessage());
}
return b;
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(Bitmap result) {
// use the result
super.onPostExecute(result);
if (mOwner != null)
mOwner.CallbackFunction(result);
}
public interface YourCallback {
void CallbackFunction(Bitmap result);
}
}
your MainActivity
public class MainActivity extends Activity implements YourCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
GetImageFromServer gifs = new GetImageFromServer(urlImage, b);
gifs.execute();
}
#Override
public void CallbackFunction(Bitmap result) {
if (person.has("Avatar")) {
Avatar.setImageBitmap(result);
}
}
}

Add an Image from url into InfoWindowAdapter

I'm trying to display an image from a URL in an InfoWindowAdapter, but it does not show me the image. I'm using Volley to load images.
Does anyone have an idea how to solve this problem?
Thanks for your help!
I got it solve the problem. It was necessary to download the image manually. How did the code:
private void loadImage(Marker marker) {
if (((BitmapDrawable) localImage
.getDrawable()) == null) {
new DownloadImage(localImage, marker).execute(urlImage);
}
private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
private ImageView icone;
private Marker marker;
public DownloadImage(ImageView imageView, Marker marker) {
icone = imageView;
this.marker = marker;
}
#Override
protected Bitmap doInBackground(String... URL) {
String imageURL = URL[0];
Bitmap bitmap = null;
try {
// Download Image from URL
InputStream input = new java.net.URL(imageURL).openStream();
bitmap = BitmapFactory.decodeStream(input);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
icone.setImageBitmap(result);
} else {
icone.setBackgroundResource(R.drawable.ic_launcher);
}
marker.showInfoWindow();
}
}

Android Error loading image view

I am trying to load an image in my imageview but it does not load any image for the link.
The link has the image but I still get empty blank space.
private class LoadImage extends AsyncTask<String, String, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected Bitmap doInBackground(String... args) {
try {
String url = "http://www.learn2crack.com/wp-content/uploads/2014/04/node-cover-720x340.png";
URL urlurl = new URL(url);
bitmap = BitmapFactory.decodeStream(urlurl.openConnection().getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap image) {
if(image != null){
img.setImageBitmap(image);
}else{
Toast.makeText(activity.getApplicationContext(), "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
}
}
}
XML
<ImageView
android:id="#+id/list_image"
android:layout_width="50dip"
android:layout_height="50dip"
/>
As you can see in the logcat stacktrace you have a network on mainthread exception becasue you are doing a network task on the 'main' thread which is also called the gui thread. You need to use an AsyncTask for this.
private class DownloadImageTask extends AsyncTask<Object, Void, Bitmap> {
#Override
protected Bitmap doInBackground(Object... args) {
Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
return bmp;
}
#Override
protected void onPostExecute(Bitmap result) {
//here do stuff with your bitmap data, also here you can interact with the gui
}
}
Also I recommend using an Image downloading library to download images off the web. They make it really easy to download images and you dont have to worry a lot about the tiny details.

How to retrieve profile picture of linkedin user android

I have tried to fetch the profile picture of linkedin user by the following url
http://api.linkedin.com/v1/people/"+userID+"/picture-url
But i'm getting file not found exception.
Try this, hopefully it should work for you or at least give you an idea how to go about it.
//picUrl is your linkedin contact image url
BitmapWorkerTask task = new BitmapWorkerTask(picUrl,mContactPic);
task.execute();
/* Async task to download the image from URL and display it in imageView*/
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{
/*contact bitmap url */
private final String mUrl;
/*contact image view*/
ImageView mView;
public BitmapWorkerTask(String aUrl, ImageView aView) {
mUrl = aUrl;
mView = aView;
}
#Override
protected Bitmap doInBackground(String... params) {
if(mBgTaskCancel) {
/*cancel the execution of this task if the mBgTaskCancel flag is true */
this.cancel(false);
} else {
/*else get the contact bitmap from the url */
final Bitmap bitmap = Utils.getBitmapFromURL(this.mUrl);
return bitmap;
}
return null;
}
#Override
protected void onPostExecute(Bitmap aBitmap) {
if (aBitmap != null) {
/*set the image bitmap if it is not null */
mView.setImageBitmap(aBitmap);
}
}
}
/**
* function to download the image from url
*/
public static Bitmap getBitmapFromURL(String aURL) {
URL lBitmapURL;
Bitmap lBitmap = null;
try {
lBitmapURL = new URL(aURL);
InputStream lInStream = lBitmapURL.openStream();
lBitmap = BitmapFactory.decodeStream(lInStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return lBitmap;
}

notifyDataSetChanged not refreshing listview

Initially I get list of data from server and set it to listview.
When scrolling down the listview, I am getting collection of data from server and calling notifydatasetchanged of my custom adapter.
At getView() method of custom adapter, I am downloading an image from server by asyntask. When it is downloaded successfully and storing it locally. Then just trying to refresh list view at onPostExecute of that asyntask. But its not getting refresh.
The log at onPostExecute is printing but listview is not getting refresh.
public void loadBitmap(MainActivity mainActivity, String imageKey,ImageView imageView, boolean isScrolling)
{
final Bitmap bitmap = getBitmapFromCache(imageKey);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.ic_launcher);
if (!isScrolling && !mCurrentTasks.contains(imageKey)
&& mainActivity.internetIsAvailable()) {
BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
mainActivity.getAdapter());
task.execute();
}
}
}
private class BitmapLoaderTask extends AsyncTask<Void, Void, Bitmap> {
private ListAdapter mListAdapter;
private String mImageKey;
public BitmapLoaderTask(String imageKey, ListAdapter adapter) {
mListAdapter = adapter;
mImageKey = imageKey;
}
#Override
protected void onPreExecute() {
mCurrentTasks.add(mImageKey);
}
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap b = null;
try {
URL url = new URL(mImageKey);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.connect();
b = BitmapFactory.decodeStream(connection.getInputStream());
if (b != null) {
int width = b.getWidth();
int height = b.getHeight();
if (width >= mMaxWidth || height >= mMaxHeight) {
while (true) {
if (width <= mMaxWidth || height <= mMaxHeight) {
break;
}
width /= 2;
height /= 2;
}
b = Bitmap.createScaledBitmap(b, width, height, false);
}
connection.disconnect();
addBitmapToCache(mImageKey, b);
return b;
}
return null;
} catch (IOException e) {
if (e != null) {
e.printStackTrace();
}
return null;
}
}
#Override
protected void onPostExecute(Bitmap param) {
mCurrentTasks.remove(mImageKey);
if (param != null) {
mListAdapter.notifyDataSetChanged();
}
}
}
your code looks right.. but i think what may be the issue is mainActivity.getAdapter() i think you should declare adapter globally like.
private AdapterYourCustomAdapter adapter;
and then in onCreate()
adapter = new AdapterYourCustomAdapter(context,arraylist(whatever constructor is));
and then pass that call it like:
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.ic_launcher);
if (!isScrolling && !mCurrentTasks.contains(imageKey)
&& mainActivity.internetIsAvailable()) {
new BitmapLoaderTask( imageKey, adapter ).execute();
}
}
Try passing the ImageView for each bitmap into the BitmapLoaderTask at construction and hold onto that ImageView as a member variable inside. When you finish loading your bitmap, use the onPostExecute method to assign that bitmap as the ImageView drawable.
private class BitmapLoaderTask extends AsyncTask<Void, Void, Bitmap> {
private String mImageKey;
private ImageView mImageView;
public BitmapLoaderTask(ImageView imageView, String imageKey) {
mImageView = imageView;
mImageKey = imageKey;
}
protected void onPreExecute() {
/* Pre execute stuff */
}
protected Bitmap doInBackground(Void... params) {
/* Your bitmap processing */
return bitmap;
}
protected void onPostExecute(Bitmap param) {
if(param != null) {
mImageView.setImageBitmap(param);
}
}
}
This is a perfect example of what AsyncTask was built to do. The doInBackground() method is run on a background thread and thus does not interfere with UI processing, but android permissions dictate that such background threads are not allowed to touch UI elements. That's what the onProgressUpdate() and onPostExecute() are for, they run quick UI updates on the main UI thread whenever doInBackground has reached an update-worthy milestone. In this case, you're using them to notify your ImageView objects when their corresponding bitmaps are ready.

Categories

Resources