I use Glide to load my image. I need to modify my image with a SimpleTarget callback, however when the image loaded to my list, and I scroll the list shows first always an other image, and than animate the right image after 1 second to the place. Without image modification and SimpleTarget everything works just fine. Here is my code.
#BindingAdapter("imageSrc")
public static void setImage(ImageView imageView, String url) {
Glide.with(imageView.getContext()).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
//the bitmap modified here
imageView.setImageBitmap(bmp);
}
});
}
is there any solution to avoid the flickering?
I'm trying to layout a custom infoWindow programmatically. I want to load a streetView preview image using Picasso but the image isn't showing up, any idea why?
private View prepareInfoView(Marker marker){
//prepare InfoView programmatically
LinearLayout infoView = new LinearLayout(EarthquakeActivity.this);
LinearLayout.LayoutParams infoViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
infoView.setOrientation(LinearLayout.VERTICAL);
// attach the above layout to the infoView
infoView.setLayoutParams(infoViewParams);
//create street view preview # top
ImageView streetViewPreviewIV = new ImageView(EarthquakeActivity.this);
// this scales the image to match parents WIDTH?, but retain image's height??
LinearLayout.LayoutParams streetViewImageViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
streetViewPreviewIV.setLayoutParams(streetViewImageViewParams);
String imageURL = "https://maps.googleapis.com/maps/api/streetview?size=200x200&location=";
String markerLongitude = Double.toString(marker.getPosition().longitude);
String markerLatitude = Double.toString(marker.getPosition().latitude);
imageURL += markerLatitude + "," + markerLongitude + "&fov=120&heading=0&pitch=0";
Log.wtf("prepareInfoView", imageURL);
Picasso.with(this).load(imageURL).into(streetViewPreviewIV);
infoView.addView(streetViewPreviewIV);
I've tried with and without the api key appending the url.
It did work for a few clicks without the key, but hasn't since, with or without. Is the because it's too slow fetching it so Android gives up and loads the info window without it? Is there a best in class way to do this?
Would another image loading library work better? Google's volley?
Also with
LinearLayout.LayoutParams
I'd like the image to stretch across the width of the info windows, i.e. match_parent, and to scale vertically to maintain original aspect ratio, how do I do this?
This is my answer
In commonsWare new class I add this flag:
#Override
public void onSuccess() {
Log.i(TAG, "image got, should rebuild window");
if (marker != null && marker.isInfoWindowShown()) {
Log.i(TAG, "conditions met, redrawing window");
marker.setTag(new Boolean("True"));
marker.showInfoWindow();
}
}
And in prepareInfoView, I test for the flags absence.
if (marker.getTag() == null ) {
Log.i("prepareInfoView", "fetching image");
Picasso.with(this).load(imageURL).fetch(new MarkerCallback(marker));
}
else {
Log.wtf("prepareInfoView", "building info window");
Party on! :)
Is the because it's too slow fetching it so Android gives up and loads the info window without it?
Picasso loads asynchronously unless the image is cached. And the way Maps V2 works is that the View you return is converted into a Bitmap, and that is what gets rendered. As a result, you have a race condition between Picasso and Maps V2 (does the image get loaded before the Bitmap gets created?), and so it is indeterminate as to whether or not any given info window will work.
You can call showInfoWindow() on the Marker after Picasso has loaded the image, so you can populate the ImageView from Picasso's cache. showInfoWindow(), called on a Marker, triggers Maps V2 to regenerate the info window.
For example, you could change your existing into() call into into(streetViewPreviewIV, new MarkerCallback(marker)), with a MarkerCallback like:
static class MarkerCallback implements Callback {
Marker marker=null;
MarkerCallback(Marker marker) {
this.marker=marker;
}
#Override
public void onError() {
Log.e(getClass().getSimpleName(), "Error loading thumbnail!");
}
#Override
public void onSuccess() {
if (marker != null && marker.isInfoWindowShown()) {
marker.showInfoWindow();
}
}
}
Would another image loading library work better? Google's volley?
They will all suffer from the same issue.
What is working for me is this:
public class MarkerCallback implements Callback {
Marker marker=null;
String URL;
ImageView userPhoto;
MarkerCallback(Marker marker, String URL, ImageView userPhoto) {
this.marker=marker;
this.URL = URL;
this.userPhoto = userPhoto;
}
#Override
public void onError() {
//Log.e(getClass().getSimpleName(), "Error loading thumbnail!");
}
#Override
public void onSuccess() {
if (marker != null && marker.isInfoWindowShown()) {
marker.hideInfoWindow();
Picasso.with(getActivity())
.load(URL)
.into(userPhoto);
marker.showInfoWindow();
}
}
}
All I figured out is,
Picasso loads image asynchronously, so when a marker shows it's info window after clicking by internally calling the method getInfoContents or getInfoWindow method ,
by this time if the image isn't already downloaded or cached by Picasso , then it is not showed on infoWindow.
Picasso tries to load the image into imageview of infoWindow when downloaded, but According to Google maps V2, the infoWindows Once loaded, can't be manipulated, so image is not shown updated on the UI.
But the infowindow view was updated actually but couldn't show for the restriction, so if you just hide and show the infowindow , it is kind of refreshed, and the images are shown on updated infoWindow. you can do this in the following way,
You need to keep the marker reference, you can keep this as Activity/Fragment's member variable.
Picasso.with(context)
.load(marker.getSnippet())
.placeholder(R.drawable.ic_placeholder)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
if (currentClickedMarker != null && currentClickedMarker.isInfoWindowShown()) {
//toggle the marker's infoWindow
currentClickedMarker.hideInfoWindow();
currentClickedMarker.showInfoWindow();
}
}
#Override
public void onError() {
}
});
I struggled with this as well, here is a solution with glide inspired from the accepted answer.
This solution did not work for me without resizing the picture to a proper size. With override() (and centerCrop) it did the trick.
Keep track of the latest picture shown
private String previousImageUrl = null;
And use it to see if you need refreshing of the current image
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(final Marker marker) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_map_info_window, null);
MyObject myObject = (MyObject) marker.getTag();
final String url = myObject.getImageUrl();
final ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
GlideApp.with(getContext()).load(url)
.override(imageWidth, imageHeight) // made the difference
.centerCrop()
.into(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
imageView.setImageDrawable(resource);
if (!TextUtils.equals(url, previousImageUrl)) {
previousImageUrl = url;
marker.showInfoWindow();
}
}
});
return view;
}
});
If you are using the accepted answer to fix the problem and it still doesn't work,
you're probably using .fit() .
in other words you should remove .fit() from your Picasso code.
It took me a couple hours to realize it.
I have trouble finding the right workflow to load images into cache.
What I want to do:
Show Progress bar
Get data from REST service and load it into SQLite database
Some objects contain urls in JSON > load these images in cache so
they are quickly loaded when needed
Dismiss Progress bar
I have all the data loaded from rest and stored in a DB,
but I'm new to caching images.
What I go so far:
- Inserted Universal Image Loader into my project
(https://github.com/nostra13/Android-Universal-Image-Loader)
- I tried
imageLoader.loadImage(url of an image, new SimpleImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
super.onLoadingStarted(imageUri, view);
//notify me the image started loading
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
//notify me the image is loaded
}
}
But when I check:
int size = MemoryCacheUtils.findCachedBitmapsForImageUri(url from that image, ImageLoader.getInstance().getMemoryCache()).size();
//show me the size
it's always zero.
My question is the following: am I going in the right direction or do I need to fix this someother way?
I found a better solution: ShutterBug (Android alternative for SDWebImage for iOs). It's easy to add urls to the ShutterbugManager and when I want to fill an ImageView (FetchableImageView in Shutterbug) with an image, it grabs the image from cache.
I have a listview which headerView has a large image. When I call
listView.addHeaderView(headerView)
my listview doesn't scroll smoothly when I remove it it start scroll fine.
I am using Aquery lib for downloading image and cashing image
AQuery aq = new AQuery(img);
aq.id(R.id.image).image(mProduct.getMobile_pic(), true, true, mActivity.getCurrentDeviceDisplayMatrics().widthPixels, 0, new BitmapAjaxCallback(){
#Override
public void callback(String url, ImageView iv, Bitmap loadedImage, AjaxStatus status){
iv.setImageBitmap(loadedImage);
}
});
first true value is turn on memory cache, second is disk cache.
What possible reason could prevent smooth scroll of listview?
i am retriving around 20 images url from an xml , and appearing them in gridview.
thing going nice except one.
when i scroll down new images start loading , but when i again scrolls up. the previously loaded images again stars loading .
how can i resolve this bug. the previously loaded image should be retained in the layout , why it is not retaining itself .
I am using the adapter extends the BaseAdapter to view the images
Gridview like any other views that inherit AdapterView only uses the amount of views that you see on the screen. So when you scroll your views going to be reused. The Adapter's responsibility is to reassign the content to the views.
So, you need to cache your bitmaps. There is a very nice tutorial about this on the Android developer side.
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
(I uses grid view in the example)
Every time you scroll, getView() method of the adapter is called.
So every time one view come in to the screen is built in the getView() method.
You build the new view in that method, I suppose you download the image when that method is called, then one solution is caching the images. If you download few images and they are small size, a simply Map with key url and value bitmap solves the problem, if not, use database.
Every time getView() is called, check first if image is in cache, if image is in cache use it to build the view, if not download it.
use LoaderImageView from this blog http://blog.blundell-apps.com/imageview-with-loading-spinner/ & add following function
public void setImageDrawable(final MyGridViewItem obj) {
mDrawable = null;
if(obj.mDrawable != null){
mDrawable = obj.mDrawable
imageLoadedHandler.sendEmptyMessage(COMPLETE);
return;
}
mSpinner.setVisibility(View.VISIBLE);
mImage.setVisibility(View.GONE);
new Thread(){
public void run() {
try {
mDrawable = getDrawableFromUrl(imageUrl);
obj.mDrawable = mDrawable;
imageLoadedHandler.sendEmptyMessage(COMPLETE);
} catch (MalformedURLException e) {
imageLoadedHandler.sendEmptyMessage(FAILED);
} catch (IOException e) {
imageLoadedHandler.sendEmptyMessage(FAILED);
}
};
}.start();
}