Luca Pellizzari
Luca Pellizzari

Reputation: 374

Lag with simple shared-element-transition using Glide

I have a very simple transition between two activities, and sometimes, the image stops in middle, lags, flashes a black color.

I have used shared-element-transitions many times with Glide, but I can't make it not lag this time.

this is the first Activity:

val intent = Intent(this, MediaZoomImageActivity::class.java)
intent.putExtra(MediaZoomActivity.ZOOM_MEDIA_URL, submission.imageUrl)

val bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this,
            post_image_parallax, ViewCompat.getTransitionName(post_image_parallax)).toBundle()

startActivity(intent, bundle)

this is the second Activity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_zoom_image)
    postponeEnterTransition()

    back.setOnClickListener { finish() }

    val url = intent.getStringExtra(ZOOM_MEDIA_URL)
    Glide.with(this)
            .load(url)
            .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE))
            .into(media_zoom_image)

    media_zoom_image.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
        override fun onPreDraw(): Boolean {
            media_zoom_image.viewTreeObserver.removeOnPreDrawListener(this)
            startPostponedEnterTransition()

            return true
        }
    })

this is the layout for the second Activity:

  1. constraintLayout
  2. -backbutton (ImageButton)
  3. -image (ImageView)

this is the animation:

<changeBounds
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200" />

It's very simple, but I can't wrap my head around it. The second image originally had some listener to use gestures, and I thought that was the reason, but commenting everything out still it does that lag. The image in the first Activity is the target of another shared-element-transition with the same transitionName, can that be the problem? Am I doing something wrong? Is it a problem with ConstraintLayout? Is there a problem with Glide?

Thanks in advance for the help.

Upvotes: 0

Views: 3704

Answers (1)

Emre Akt&#252;rk
Emre Akt&#252;rk

Reputation: 3346

Instead using PreDrawListener, using listener with glide would fix it. Looks like there is a timing issue

 Glide
            .with(this)
            .asBitmap()
            .load(url)
            .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE))
            .listener(new RequestListener<Bitmap>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                    return false;
                }

                @Override
                public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                    media_zoom_image.setImageBitmap(resource);
                    startPostponedEnterTransition();
                    return true;
                }
            })
            .into(media_zoom_image);

Make sure you remove

 media_zoom_image.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
        media_zoom_image.viewTreeObserver.removeOnPreDrawListener(this)
        startPostponedEnterTransition()

        return true
    }
})

UPDATE

I have updated onResourceReady block. Give it a try please.

Glide
        .with(this)
        .asBitmap()
        .load(url)
        .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE))
        .listener(new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                startPostponedEnterTransition();
                return false;
            }
        })
        .into(media_zoom_image);

UPDATE 2

Call postponeEnterTransition as early as possible.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);

postponeEnterTransition(); // Called it before set content. Try to call it before super.onCreate to see if it also works?

setContentView(R.layout.activity_zoom_image);
...
})

UPDATE 3

Optimize your images. There are some online websites or tools for it, or you can ask your graphic designer.

Also you can increase duration of animation to give time for smooth loading.

<changeBounds
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300" />

Notice that the listener in glide, runs before setting bitmap to view. Difference between Picasso and Glide, Picasso has callback parameter in into() method as optional, whichs runs onSuccess() after setting bitmap to view. So the execution which makes our shared transition is choppy (ImageView#setBitmapImage) already ran while postponed. Picasso has shining little bit more in this situation.

Upvotes: 3

Related Questions