I am getting json data. In that json I have a url for an image. Now I want to display that Image in ImageView. How can I do acheive this? Here is my code
class LoadInbox extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Home.this);
pDialog.setMessage("Loading Inbox ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting Inbox JSON
* */
protected String doInBackground(String... arg0) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = userFunctions.homeData();
Log.e("Data", json.toString());
// Check your log cat for JSON reponse
Log.d("Inbox JSON: ", json.toString());
try {
data = json.getJSONArray(TAG_DATA);
Log.d("inbox array: ", data.toString());
// looping through All messages
for (int i = 0; i < data.length(); i++) {
JSONObject c = data.getJSONObject(i);
// Storing each json item in variable
String profile_img = c.getString(TAG_PROFILE_IMG);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_PROFILE_IMG, profile_img);
// adding HashList to ArrayList
inboxList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
Home.this, inboxList,
R.layout.home_list_item, new String[] { TAG_PROFILE_IMG },
new int[] { R.id.profile_img2 });
// updating listview
setListAdapter(adapter);
}
});
}
here is my layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/profile_img2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="8dip"
android:paddingLeft="8dip"
android:paddingBottom="4dip" />
</RelativeLayout>
So you'll want to create another AsyncTask that given a URL will load the image, and populate some control. I typically do something like this:
ImageView imageView = (ImageView)findById(R.id.blah);
new ImageLoader( person.getImageUri(), imageView, 128, 128 ).execute();
The ImageLoader would be another AsyncTask like this:
public class ImageLoader extends AsyncTask<URI,Integer,BitmapDrawable> {
private Uri imageUri;
private ImageView imageView;
private int preferredWidth = 80;
private int preferredHeight = 80;
public ImageLoader( URI uri, ImageView imageView, int scaleWidth, int scaleHeight ) {
this.imageUri = uri;
this.imageView = imageView;
this.preferredWidth = scaleWidth;
this.preferredHeight = scaleHeight;
}
public BitmapDrawable doInBackground(URI... params) {
if( imageUri == null ) return null;
String url = imageUri.toString();
if( url.length() == 0 ) return null;
HttpGet httpGet = new HttpGet(url);
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute( httpGet );
InputStream is = new BufferedInputStream( response.getEntity().getContent() );
try {
Bitmap bitmap = BitmapFactory.decodeStream(is);
if( preferredWidth > 0 && preferredHeight > 0 && bitmap.getWidth() > preferredWidth && bitmap.getHeight() > preferredHeight ) {
return Bitmap.createScaledBitmap(bitmap, preferredWidth, preferredHeight, false);
} else {
return bitmap;
}
} finally {
is.close();
}
}
}
public void onPostExecute( BitmapDrawable drawable ) {
imageView.setImageBitmap( drawable );
}
}
Then you can kick this AsyncTask off when the image is being bound in your ListView by creating your own subclass ListAdapter. So you'll have to ditch using SimpleAdapter because things aren't simple anymore. This has a lot of advantages so you only load the images being displayed. That means a very small number is loaded out of the total. Also your user can see the data before the image loads so quicker access to the data. If you did this in your existing AsyncTask you'd load every image, and the user would have to wait for every single one to finish before the data is shown to the user. There are somethings that can be improved by this. One AsyncTask uses its own thread so you'll be running a lot of threads potentially (10 or more) all at once. That can kill your server with lots of clients. You can centralize these using an ExecutorService (ie thread pool) but you'll have to ditch using AsyncTask and implement your own facility to run the job off the UI thread and post the results back on the UI thread. Second, your images will load every time the user scrolls. For this I implemented my own caching scheme based on the URI of the image so I only load the image once and return it from the cache. It's a little too much code to post here, but these are exercises for the reader.
Also notice I'm not posting back to the UI thread in onPostExecute(). That's because AsyncTask does that for me I don't have to do it again as your code above shows. You should just remove that extra runnable and inline the code in onPostExecute().
you can try picasso is really easy to use and works really well.
Picasso.with(this.getActivity()).load(person.getImageUri()).into(imageView); // if person.getImageUri() has the url image loaded from json
And that's it.
As it looks you are getting the more than one url (as in array)
1- Keep all the url in an hastable with key as url and value as image View.
2- Show your UI and with loading image.
3- create the other task download image one by one and update in the image view.
as example lazy imageloader......
http://iamvijayakumar.blogspot.in/2011/06/android-lazy-image-loader-example.html
http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/
Android Out of Memory error with Lazy Load images
Android lazy loading images class eats up all my memory
Lazy Load images on Listview in android(Beginner Level)?
Lazy load of images in ListView
Related
Need to generate thumbnail from video stored in server, below is my code but "path" variable is giving problem, how to get it resolved. If i remove path parameter with url parameter then i am getting the thumbnails but not in proper order or sometimes same thumbnail is generated for 2 or 3 videos, below is my code -
Video video = mVideos.get(position);
//play video using android api, when video view is clicked.
url = video.getVideoUrl(); // your URL here
Uri videoUri = Uri.parse(url);
new DownloadImage(holder.videothumbView).execute(url);
public class DownloadImage extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImage(ImageView bmImage) {
this.bmImage = (ImageView ) bmImage;
}
protected Bitmap doInBackground(String... urls) {
Bitmap myBitmap = null;
MediaMetadataRetriever mMRetriever = null;
try {
mMRetriever = new MediaMetadataRetriever();
if (Build.VERSION.SDK_INT >= 14)
mMRetriever.setDataSource(path, new HashMap<String, String>());
else
mMRetriever.setDataSource(path);
myBitmap = mMRetriever.getFrameAtTime();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mMRetriever != null) {
mMRetriever.release();
}
}
return myBitmap;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
All the network related task must be done in a separate thread. You can't do it in main thread. You can use Picasso image library. It is open source and you can show different image for different state like loading, error etc.
Picasso.with(context) // your activity of other context referance
.load(video.getVideoUrl())
.placeholder(R.drawable.user_placeholder) // this will show during image loading from network
.error(R.drawable.user_placeholder_error) // error image to display
.into(holder.videothumbView);
I new in the developping of android applications using ArcGIS android runtime API.
I am trying to zoom to an extend and hightlights that extend . But it is not working in my case.
Feature layer url ishttps://services7.arcgis.com/7FyZZrSIYfiWYztL/ArcGIS/rest/services/MyGisFileTest/FeatureServer/0
which is getting from ArcGIS online portal.
i have added the layer in the map
ArcGISFeatureLayer fl1 = new ArcGISFeatureLayer(
"https://services7.arcgis.com/7FyZZrSIYfiWYztL/ArcGIS/rest/services/MyGisFileTest/FeatureServer/0",
ArcGISFeatureLayer.MODE.ONDEMAND);
fl1.setOnStatusChangedListener(statusChangedListener);
mMapView.addLayer(fl1);
Here i am getting my ward_name from the user input by using the edittext andi am submitting that to an asyn class to fetch data .
I am calling the sync task on button click and passing the user inputed values to the async task.
declaration section
//query task
private Callout mCallout;
private ViewGroup mCalloutContent;
private Graphic mIdentifiedGraphic;
private String mFeatureServiceURL;
private GraphicsLayer mGraphicsLayer;
private ProgressDialog progress;
EditText _EdtTxtTextToZoom;
Button _BtnZoomToExtend;
In my oncreate method i am definig all the things
mGraphicsLayer = new GraphicsLayer();
mMapView.addLayer(mGraphicsLayer);
LayoutInflater inflater = getLayoutInflater();
mCallout = mMapView.getCallout();
// Get the layout for the Callout from
// layout->identify_callout_content.xml
mFeatureServiceURL="https://services7.arcgis.com/7FyZZrSIYfiWYztL/ArcGIS/rest/services/MyMapService/FeatureServer/0";
mCalloutContent = (ViewGroup) inflater.inflate(R.layout.identify_callout_content, null);
mCallout.setContent(mCalloutContent);
mIdentifiedGraphic = getFeature(fl1);
_EdtTxtTextToZoom=(EditText)findViewById(R.id.EdtTxtTextToZoom);
_BtnZoomToExtend=(Button)findViewById(R.id.BtnZoomToExtend);
_BtnZoomToExtend.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String tempEdtTxtTextToZoom= "";
try {
tempEdtTxtTextToZoom = _EdtTxtTextToZoom.getText().toString();
new QueryFeatureLayer().execute(tempEdtTxtTextToZoom);
} catch (NumberFormatException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "tempEdtTxtTextToZoom.."+tempEdtTxtTextToZoom, Toast.LENGTH_SHORT).show();
}
});
AsyncTask
private class QueryFeatureLayer extends AsyncTask<String, Void, FeatureResult> {
// default constructor
public QueryFeatureLayer() {
}
#Override
protected void onPreExecute() {
progress = ProgressDialog.show(MainActivity.this, "", "Please wait....query task is executing");
}
#Override
protected FeatureResult doInBackground(String... params) {
Log.e("params[0]--",params[0]);
String whereClause = "ward_name ='" + params[0] + "'";
Log.e("whereClause--",whereClause);
// Define a new query and set parameters
QueryParameters mParams = new QueryParameters();
mParams.setWhere(whereClause);
mParams.setReturnGeometry(true);
// Define the new instance of QueryTask
QueryTask queryTask = new QueryTask(mFeatureServiceURL);
FeatureResult results;
try {
// run the querytask
results = queryTask.execute(mParams);
Log.e("results---", String.valueOf(results));
return results;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(FeatureResult results) {
// Remove the result from previously run query task
mGraphicsLayer.removeAll();
// Define a new marker symbol for the result graphics
SimpleMarkerSymbol mGreenMarkerSymbol = new SimpleMarkerSymbol(Color.GREEN, 15, SimpleMarkerSymbol.STYLE.CIRCLE);
// Envelope to focus on the map extent on the results
Envelope extent = new Envelope();
// iterate through results
for (Object element : results) {
// if object is feature cast to feature
if (element instanceof Feature) {
Feature feature = (Feature) element;
// convert feature to graphic
Graphic graphic = new Graphic(feature.getGeometry(), mGreenMarkerSymbol, feature.getAttributes());
// merge extent with point
extent.merge((Point)graphic.getGeometry());
Log.e("points----", String.valueOf(graphic.getGeometry()));
// add it to the layer
mGraphicsLayer.addGraphic(graphic);
}
}
Log.e("points----", String.valueOf(extent));
// Set the map extent to the envelope containing the result graphics
mMapView.setExtent(extent, 100);
// Disable the progress dialog
progress.dismiss();
}
}
Can you please figure it out where i am doing the mistake ?
In the above example im trying to zoom points but actually i wanted the polygon Below is the correct code to zoom a particular polygons extent
for (Object element : results) {
progress.incrementProgressBy(size / 100);
if (element instanceof Feature) {
Feature feature = (Feature) element;
// turn feature into graphic
Graphic graphic = new Graphic(feature.getGeometry(),
feature.getSymbol(), feature.getAttributes());
Polygon p = (Polygon) graphic.getGeometry();
p.queryEnvelope(extent);
extent.merge(extent);
// add graphic to layer
mGraphicsLayer.addGraphic(graphic);
I've spent few days to solve this problem but still can't find a solution. I'm new to Android so my code might be pretty messy!
I have a RecyclerView(Grid layout) that displays thumbnails for images and videos. It loads media files in a specific folder. But when I launch this activity, it takes up so much memory!
To load thumbnails, I created two threads.
Thread 1) MediaLoadThread that queries media files in SDCard. It loops through the cursor and queue thumbnail decode tasks to the different thread.
Thread 2) ThumbnailLoaderThread that decode each individual thumbnail. It receives the content resolver, media type(image or video), and media id. It uses basic .getThumbnail() method. After it's done with getting thumbnail, it triggers the response callback to it's caller thread(MediaLoadThread).
3) When MediaLoadThread(Thread 1) receives the callback, it triggers another callback that lets the activity update the adapter item of the given position. The adapter updates the UI and finally the thumbnail ImageView changes from placeholder to actual thumbnail.
:::Here's my code:::
1) MediaLoadThread.java
#Override
public void run() {
mMediaDataArr.clear();
mLoaderThread.start(); // Prepping the thread 2
mLoaderThread.prepareHandler();
// .... SD Card query stuff .....
if (mediaCursor != null && mediaCursor.moveToFirst()) {
do {
mMediaDataArr.add(new MediaData(videoCursor.getInt(columnIndexId),
mediaCursor.getLong(columnIndexDate), //ID
mediaCursor.getInt(columnIndexType), //MEDIA TYPE
null); //THUMBNAIL BITMAP (NULL UNTIL THE ACTUAL THUMBNAIL IS DECODED)
} while (mediaCursor.moveToNext());
mediaCursor.close();
mResponseHandler.post(new Runnable() {
#Override
public void run() {
// This callback lets the activity activate the adapter and recyclerview so that the user can interact with recyclerview before the app finishes decoding thumbnails.
mCallback.onVideoLoaded(mMediaDataArr);
}
});
//Passing tasks to thread 2
for (int i = 0; i < mMediaDataArr.size(); i++) {
mLoaderThread.queueTask(
mMediaDataArr.get(i).getmMediaType(),
i, mMediaDataArr.get(i).getmMediaId());
}
}
}
}
// This is triggered by thread 2 when it finishes decoding
#Override
public void onThumbnailLoaded(final int position, final Bitmap thumbnail) {
mResponseHandler.post(new Runnable() {
#Override
public void run() {
mCallback.onThumbnailPrepared(position, thumbnail);
}
});
}
2) ThumbnailLoaderThread.java
public void queueTask(int mediaType, int position, int videoId) {
mWorkerHandler.obtainMessage(mediaType, position, videoId).sendToTarget();
}
public void prepareHandler() {
mWorkerHandler = new Handler(getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
int type = msg.what;
final int position = msg.arg1;
int videoId = msg.arg2;
try {
if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) {
Bitmap newThumb = MediaStore.Images.Thumbnails
.getThumbnail(mCr, videoId,
MediaStore.Images.Thumbnails.MINI_KIND, null);
postResult(position, newThumb);
} else if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
Bitmap newThumb = MediaStore.Video.Thumbnails
.getThumbnail(mCr, videoId,
MediaStore.Video.Thumbnails.MINI_KIND, null);
postResult(position, newThumb);
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
});
}
private void postResult(final int position, final Bitmap newThumb) {
mResponseHandler.post(new Runnable() {
#Override
public void run() {
mCallback.onThumbnailLoaded(position, newThumb);
}
});
}
3) LibraryActivity.java
#Override
public void onThumbnailPrepared(int position, Bitmap thumbnail) {
if (thumbnail != null && position < mData.size()) {
MediaData updatedData = mData.get(position);
updatedData.setmThumbnail(thumbnail);
mData.set(position, updatedData);
mVideoAdapter.notifyItemChanged(position);
}
}
The flow is like this.
1) The activity starts the thread 1.
2) Thread 1 starts querying files and starts thread 2. It passes the media id looping through the cursor.
3) Thread 2 decodes thumbnails with the given media id.
4) When decoding is done, thread 2 triggers the callback to Thread 1 with the result bitmap.
5) Thread 1 receives the bitmap and delivers the bitmap to activity through callback.
6) Activity receives the thumbnail and updates the RecyclerView data with the given bitmap.
It works fine, but when the system allocates almost 50MB of memory for this task... Considering it was only loading 100 thumbnails, I think it's pretty heavy.
:::What I've tried:::
1) I extracted the URI of each individual thumbnail and let the recyclerview adapter to load the image with the given URI when it binds. It works fine and did not consume that much memory, but because it loads images when the item is bound, it reloads the thumbnail whenever I scroll the screen with a little bit of delay.
2) I let the adapter to load thumbnails with the direct thumbnail path. But it won't work when the user cleans up the /.thumbnails folder.
3) I set the BitmapFactory.Options samplsize into 4 when the thread decodes thumbnails. But when it was still heavy and even slower sometimes...
4) In MediaData object, it holds the thumbnail bitmap as a member variable. So I made it null right after the adapter loaded it into the ImageView. Still heavy, and because I made the object's thumbnail into null, it just shows the placeholder when I scroll back.
I really have no clue. Any help would be appreciated!!
You can used nostra universal image loader library to load images. This library is very good for image loading and also some other library like Picasso, glide etc available which you can used instead of making manual coding.
I have a sliding menu and an action bar in my Android app.
At the top of the sliding menu there is a user name and a user picture
If I set them once, they are lost when I close and open the menu again.
So every time its opened Im calling a user details downloader class and Im setting the name and the avatar again, which is very irritating.
How can I set them once and dont bother with this until the app is closed, no matter whether the sliding menu is opened or closed?
public class AsdActionBarAndSlidingMenu extends AsdActionBar implements IOnUserDetailsAndStatsReceivedListener{
private TextView tvSlidingMenuUserName;
private Typeface font2;
private UserDetailsAndStatsDownloader mUserDetailsDownloader;
private String userName;
private ImageView ivSlidingMenuUserAvatar;
private String avatarPath;
private Bitmap ivSlidingMenuUserBitmap;
private static final String APP_SHARED_PREFS = "asdasd_prefs";
SharedPreferences sharedPrefs;
public Editor editor;
protected int currentlyLoggedInUser;
protected String currentlyLoggedInUserString;
public AsdActionBarAndSlidingMenu(int titleRes) {
super(R.string.app_name);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setBehindContentView(R.layout.menu_frame);
sharedPrefs = getApplicationContext().getSharedPreferences(APP_SHARED_PREFS, Context.MODE_PRIVATE);
currentlyLoggedInUser = sharedPrefs.getInt("currentLoggedInUserId", 0);
currentlyLoggedInUserString = Integer.toString(currentlyLoggedInUser);
tvSlidingMenuUserName = (TextView) findViewById(R.id.tvSlidingMenuUserName);
tvSlidingMenuUserName.setTypeface(font2);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.menu_frame, new AsdSlidingMenuListFragment()).commit();
getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
setSlidingActionBarEnabled(true);
getSlidingMenu().setOnOpenedListener(new OnOpenedListener() {
#Override
public void onOpened() {
mUserDetailsDownloader = new UserDetailsAndStatsDownloader(currentlyLoggedInUserString, AsdActionBarAndSlidingMenu.this, AsdActionBarAndSlidingMenu.this);
mUserDetailsDownloader.downloadUserDetailsAndStats();
}
});
}
#Override
public void onUserDetailsAndStatsReceivedListener(UserDetailsAndStats userDetailsAndStats) {
userName = userDetailsAndStats.getUserName();
tvSlidingMenuUserName = (TextView) findViewById(R.id.tvSlidingMenuUserName);
tvSlidingMenuUserName.setText(userName);
avatarPath = userDetailsAndStats.getUserAvatar();
ivSlidingMenuUserBitmap = BitmapFactory.decodeFile(avatarPath);
ivSlidingMenuUserAvatar = (ImageView) findViewById(R.id.ivSlidingMenuUserAvatar);
ivSlidingMenuUserAvatar.setImageBitmap(ivSlidingMenuUserBitmap);
}
}
But, what gets unset is the BitMap, or the Views (ivSlidingMenuUserAvatar and tvSlidingMenuUserName)?
I dont know how you created UserDetailsAndStatsDownloader, but probably onUserDetailsAndStatsReceivedListener is called in a diferent thread. That could cause that when that thread is not running, and those views are unused, you can lose them. But im not sure.
Anyways, try to inflating the views in you onCreate, and also retrieving the data after that
public void onCreate(Bundle savedInstanceState) {
...
tvSlidingMenuUserName = (TextView) findViewById(R.id.tvSlidingMenuUserName);
ivSlidingMenuUserAvatar = (ImageView) findViewById(R.id.ivSlidingMenuUserAvatar);
mUserDetailsDownloader = new UserDetailsAndStatsDownloader(currentlyLoggedInUserString, AsdActionBarAndSlidingMenu.this, AsdActionBarAndSlidingMenu.this);
mUserDetailsDownloader.downloadUserDetailsAndStats();
}
and let the listener just like this
#Override
public void onUserDetailsAndStatsReceivedListener(UserDetailsAndStats userDetailsAndStats){
userName = userDetailsAndStats.getUserName();
tvSlidingMenuUserName.setText(userName);
avatarPath = userDetailsAndStats.getUserAvatar();
ivSlidingMenuUserBitmap = BitmapFactory.decodeFile(avatarPath);
ivSlidingMenuUserAvatar.setImageBitmap(ivSlidingMenuUserBitmap);
}
then, remove getSlidingMenu().setOnOpenedListener(...) and lets see what happend.
Besides, you should use any cache method for your downloads, so even if you need to download again file, if you have already done, no network operation is involved. For example you can do it like is shown in android-imagedownloader that is a really easy example.
/*
* Cache-related fields and methods.
*
* We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the
* Garbage Collector.
*/
private static final int HARD_CACHE_CAPACITY = 10;
private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds
// Hard cache, with a fixed maximum capacity and a life duration
private final HashMap<String, Bitmap> sHardBitmapCache =
new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
#Override
protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
if (size() > HARD_CACHE_CAPACITY) {
// Entries push-out of hard reference cache are transferred to soft reference cache
sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
return true;
} else
return false;
}
};
// Soft cache for bitmaps kicked out of hard cache
private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =
new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);
private final Handler purgeHandler = new Handler();
private final Runnable purger = new Runnable() {
public void run() {
clearCache();
}
};
/**
* Adds this bitmap to the cache.
* #param bitmap The newly downloaded bitmap.
*/
private void addBitmapToCache(String url, Bitmap bitmap) {
if (bitmap != null) {
synchronized (sHardBitmapCache) {
sHardBitmapCache.put(url, bitmap);
}
}
}
/**
* #param url The URL of the image that will be retrieved from the cache.
* #return The cached bitmap or null if it was not found.
*/
private Bitmap getBitmapFromCache(String url) {
// First try the hard reference cache
synchronized (sHardBitmapCache) {
final Bitmap bitmap = sHardBitmapCache.get(url);
if (bitmap != null) {
// Bitmap found in hard cache
// Move element to first position, so that it is removed last
sHardBitmapCache.remove(url);
sHardBitmapCache.put(url, bitmap);
return bitmap;
}
}
// Then try the soft reference cache
SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);
if (bitmapReference != null) {
final Bitmap bitmap = bitmapReference.get();
if (bitmap != null) {
// Bitmap found in soft cache
return bitmap;
} else {
// Soft reference has been Garbage Collected
sSoftBitmapCache.remove(url);
}
}
return null;
}
/**
* Clears the image cache used internally to improve performance. Note that for memory
* efficiency reasons, the cache will automatically be cleared after a certain inactivity delay.
*/
public void clearCache() {
sHardBitmapCache.clear();
sSoftBitmapCache.clear();
}
If we have the code of the rest of the classes involved (just the ones you writed) the help could be much more accurate.
This line of code is responsible for loading the bitmap from the avatarPath, right?
ivSlidingMenuUserBitmap = BitmapFactory.decodeFile(avatarPath);
If you want to do it once and forever, you should only do this decoding once and store the value of it elsewhere in your code. You've already stored the value in a field, so you shouldn't need to keep decoding it from the file.
Adding a simple if (ivSlidingMenuUserBitmap != null) before that line should prevent that. Like so:
avatarPath = userDetailsAndStats.getUserAvatar();
if (ivSlidingMenuUserBitmap != null)
ivSlidingMenuUserBitmap = BitmapFactory.decodeFile(avatarPath);
ivSlidingMenuUserAvatar = (ImageView) findViewById(R.id.ivSlidingMenuUserAvatar);
ivSlidingMenuUserAvatar.setImageBitmap(ivSlidingMenuUserBitmap);
I am implementing a DrawerLayout and one of the items
or the menu of the drawer displays a gridview with images which is also a fragment.
The problem is by the time I click on the item, there is this delay or lag before the grid
of images will be showed.
Been searching for this, and I'd like to have an AsyncTask to make sure that the GridView fragment
should be completely loaded before displaying which I need to have a ProgressDialog to prevent the lag
effect or to cover up the view. How do I check if the fragment is ready to be displayed? How do
I handle the AsyncTask? Thanks in advance.
ImageGridActivity fragment = new ImageGridActivity();
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.fragment_planet_replace, fragment);
Bundle args = new Bundle();
args.putStringArray(Extra.IMAGES, Constants.IMAGES);
fragment.setArguments(args);
ft.addToBackStack(null);
ft.commit();
EDIT:
I am using an `ImageAdapter` to populate the images to the listview.
`listView.setAdapter(new ImageAdapter());`
I am using Universal-Image-Loader to handle the downloading of images and displaying it.
imageLoader.displayImage
You could launch a new AsyncTask that downloads the images in its doInBackground method (which runs on a background thread) and dismisses the ProgressDialog in its onPostExecute method (which runs on the UI thread).
For example, in your Activity:
final Dialog progressDialog = ProgressDialog.show(this, title, message);
//Should use DialogFragment to wrap the ProgressDialog
new AsyncTask<String, Void, List<byte[]>>(){
#Override
protected List<byte[]> doInBackground(String... urls) {
List<byte[]> imageList = new ArrayList<byte[]>();
HttpURLConnection conn = null;
byte[] buffer = new byte[BUFF_SIZE];
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(BUFF_SIZE);
//Add try - catch - finally block
for(String targetUrl : urls){
conn = (HttpURLConnection)new URL(targetUrl).openConnection();
InputStream iStream = new BufferedInputStream(conn.getInputStream());
int len = 0;
//Alternatively could use Apache Commons IO
while ((len = iStream.read(buffer)) >= 0) {
byteBuffer.write(buffer, 0, len);
}
imageList.add(byteBuffer.toByteArray());
byteBuffer.reset();
}
return imageList;
}
#Override
protected void onPostExecute(List<byte[]> result) {
progressDialog.dismiss();
listView.setAdapter(new ImageAdapter(result)); //Example
super.onPostExecute(result);
}
}.execute(imageUrl1, imageUrl2, imageUrl3);