How to delay Picasso image loading? - android

I have implemented a shared element activity transition animation between MainActivity (GridView) and DetailActivity. When item is clicked, the image in Grid item will zoom-in to become the background image in DetailActivity. I have made the transition very smooth by saving the image on the MainActivity into a file, then use it as placeholder image in DetailActivity before the higher quality image is downloaded via picasso. When picasso finished its task the higher quality image will replace the placeholder one very neatly.
Code from onCreateView() in DetailActivityFragment.java
ImageView iv = (ImageView) mRootview.findViewById(R.id.movie_poster);
try {
// Prepare "InterimPoster" jpeg file to be placeholder image
Bitmap bitmap = BitmapFactory.decodeStream(c.openFileInput("InterimPoster"));
Picasso.with(c).load("http://image.tmdb.org/t/p/w780" + mMovieInfo[2])
.placeholder(new BitmapDrawable(getResources(), bitmap))
.fit()
.centerCrop()
.noFade()
.into(iv);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
As for animation, I implement it like in the link here step 1-3 https://guides.codepath.com/android/Shared-Element-Activity-Transition
However, sometimes there's flicker when the higher quality image finished download before the transition animation is completed. The zooming-in image will be replaced with new image while moving which is an unpleasant animation.
So I wonder how can I fix this flicker? One thing I can think of is to delay the image download because I already have lower quality image as a placeholder. How can I do that?
Here the video.
Usually, on my test device it's smooth 80% of the time, but luckily in this video it flicker most of the time.

what's animation ? load image while animation end
TranslateAnimation translateAnimation = new TranslateAnimation(0,1.5f,0,1.5f);
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
//load image when animation end
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
and
LayoutTransition.TransitionListener transitionListener = new LayoutTransition.TransitionListener() {
#Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
}
#Override
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
//load image when animation end
}
};

Now I have found a way to delay Picasso image loading (or any other task). It's very simple really with the use of Handler and Runnable.
Now my code looks like this. The image replacement is pretty smooth in any case now.
// Set Background Poster in Try-catch in case file cannot be open
try {
// Get/Prepare "InterimPoster" jpeg file to be placeholder image
final ImageView iv = (ImageView) mRootview.findViewById(R.id.movie_poster);
final Bitmap bitmap = BitmapFactory.decodeStream(c.openFileInput("InterimPoster"));
final Drawable lowResPoster = new BitmapDrawable(getResources(), bitmap);
iv.setImageDrawable(lowResPoster);
// Download higher resolution image with 0.8 sec delay to avoid load complete before
// animation finishes (causing some flicker/overflow image problem).
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
Picasso.with(c).load("http://image.tmdb.org/t/p/w780" + mMovieInfo[2])
// still need placeholder here otherwise will flash of white image
.placeholder(lowResPoster)
.error(lowResPoster)
.fit()
.centerCrop()
.noFade() // without this image replacement will not be smooth
.into(iv);
}
};
handler.postDelayed(runnable, 800);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

Try the below code:
First use picasso normally to load placeholder into the imageview
iv.setImageBitmap(bitmap);
Then use SharedElement Listener like this
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();sharedElementEnterTransition.addListener(new TransitionListenerAdapter() {
#Override
public void onTransitionEnd(android.support.transition.Transition transition) {
super.onTransitionEnd(transition);
Picasso.with(c).load("http://image.tmdb.org/t/p/w780" + mMovieInfo[2])
.placeholder(new BitmapDrawable(getResources(), bitmap))
.fit()
.centerCrop()
.noFade()
.into(iv);
}
});

To delay some process, you can use Handler().
Example.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// write your codes here.. this will delay 2 seconds...
startActivity(new Intent(this,MySecondActivity.class);
}
},2000);

Related

How to use Glide's SimpleTarget with databinding?

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?

picasso image not loading in custom infoWindow why?

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.

Picasso loads image with triangle in corner of image

I'm using picasso library for loading images from server into my application. my problem is when image loaded it has a triangle in top-left corner of image with color(like blue,green,red).
this is my code for loading image:
public static void loadDynamicImage(final String url, final Context context, final ImageView imageView, final int width, final int height){
Picasso.with(context).load(url)
.networkPolicy(NetworkPolicy.OFFLINE)
.resize(width,height)
.onlyScaleDown()
.into(imageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(context).load(url).resize(width,height).onlyScaleDown().into(imageView);
}
});
}
the image shown is :
You have enabled debug indicators on your Picasso instance (see official website). Look for setIndicatorsEnabled(true) in your code and remove it.
You have setIndicatorsEnabled set to true
Picasso picasso = Picasso.with(this);
picasso.setIndicatorsEnabled(false); //Or remove picasso.setIndicatorsEnabled(true);
Check this: Is there any way from which we can detect images are loading from cache in picasso?

Progress dialog in imageview until i load image from server

How can I add the Progress dialog in ImageView until I loading image from server in android. When image download complete then display the image.
try {
cachedImage = imageLoader.loadImage(mTopicList.getTopicImage(j),
new ImageLoadedListener() {
public void imageLoaded(Bitmap imageBitmap)
{
imageView.setImageBitmap(imageBitmap);
imageView.invalidate();
}
});
} catch (Exception e) {
e.printStackTrace();
}
Approach which I followed to do this. Use the Frame Layout and have a ImageView and ProgressBar inside it. I've used the Universal Image Loader Library, which have callback once image has been downloaded. Initially show the ProgressBar and hide the ImageView to invisible. Once image has been downloaded then hide the ProgressBar and show the image in the ImageView.
Initially
imageView.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.VISIBLE);
Load your image now. After loading it, call this:
progressBar.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.VISIBLE);
Hope this help to you all!

Android: how to change a low quality image to the hi quality one when the animation stops in gallery?

I want to do an image gallery like in iphone. I want to show low quality (pre-resized) images and when the image is active I want to process the big image and show the result in the gallery.
I have two questions. How to attach a listener on the animation stop in gallery? And how to access an image after this action?
You can set an AnimationListener on your animation, and override the onAnimationEnd method.
From http://www.roosmaa.net/animation-ended-callback/ :
ImageView viewN = ..;
Animation animN = ...;
Drawable myNewDrawable = ...;
animN.setAnimationListener(new AnimationListener() {
// ...
void onAnimationEnd(Animation anim)
{
//Do your work here.
viewN.setDrawable(myNewDrawable);
return;
}
// ...
});
viewN.startAnimation(animN);

Categories

Resources