Skip to content

Instantly share code, notes, and snippets.

@fesago90
Last active February 20, 2019 14:29
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fesago90/ae7a56628c35e65ddaab to your computer and use it in GitHub Desktop.
Save fesago90/ae7a56628c35e65ddaab to your computer and use it in GitHub Desktop.
shared element transition mem leak fix
package com.dopplerlabs.hereactivelistening.hacks;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.SharedElementCallback;
import android.view.View;
import android.widget.ImageView;
/**
* Created by Felipe on 12/4/15.
*
* In your activities add the following code on creation:
* ActivityCompat.setEnterSharedElementCallback(this, new LeakFreeSupportSharedElementCallback());
* ActivityCompat.setExitSharedElementCallback(this, new LeakFreeSupportSharedElementCallback());
*
*/
public class LeakFreeSupportSharedElementCallback extends SharedElementCallback {
static final String BUNDLE_SNAPSHOT_BITMAP = "BUNDLE_SNAPSHOT_BITMAP";
static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "BUNDLE_SNAPSHOT_IMAGE_SCALETYPE";
static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "BUNDLE_SNAPSHOT_IMAGE_MATRIX";
static final String BUNDLE_SNAPSHOT_TYPE = "BUNDLE_SNAPSHOT_TYPE";
static final String BUNDLE_SNAPSHOT_TYPE_IMAGE_VIEW = "BUNDLE_SNAPSHOT_TYPE";
Matrix mTempMatrix;
@Override
public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix,
RectF screenBounds) {
if (sharedElement instanceof ImageView) {
ImageView imageView = ((ImageView) sharedElement);
Drawable d = imageView.getDrawable();
Drawable bg = imageView.getBackground();
if (d != null && (bg == null || bg.getAlpha() == 0)) {
Bitmap bitmap = TransitionUtils.createDrawableBitmap(d);
if (bitmap != null) {
Bundle bundle = new Bundle();
bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap);
bundle.putString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE,
imageView.getScaleType().toString());
if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
Matrix matrix = imageView.getImageMatrix();
float[] values = new float[9];
matrix.getValues(values);
bundle.putFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX, values);
}
bundle.putString(BUNDLE_SNAPSHOT_TYPE, BUNDLE_SNAPSHOT_TYPE_IMAGE_VIEW);
return bundle;
}
}
}
if (mTempMatrix == null) {
mTempMatrix = new Matrix(viewToGlobalMatrix);
} else {
mTempMatrix.set(viewToGlobalMatrix);
}
Bundle bundle = new Bundle();
Bitmap bitmap = TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds);
bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap);
return bundle;
}
@Override
public View onCreateSnapshotView(Context context, Parcelable snapshot) {
View view = null;
if (snapshot instanceof Bundle) {
Bundle bundle = (Bundle) snapshot;
Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP);
if (bitmap == null) {
bundle.clear();
return null;
}
// Curiously, this is required to have the bitmap be GCed almost immediately after transition ends
// otherwise, garbage-collectable mem will still build up quickly
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
if (bitmap == null) {
return null;
}
if (BUNDLE_SNAPSHOT_TYPE_IMAGE_VIEW.equals(((Bundle)snapshot).getString(BUNDLE_SNAPSHOT_TYPE))) {
ImageView imageView = new ImageView(context);
view = imageView;
imageView.setImageBitmap(bitmap);
imageView.setScaleType(
ImageView.ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE)));
if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
float[] values = bundle.getFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX);
Matrix matrix = new Matrix();
matrix.setValues(values);
imageView.setImageMatrix(matrix);
}
} else {
view = new View(context);
Resources resources = context.getResources();
view.setBackground(new BitmapDrawable(resources, bitmap));
}
bundle.clear();
}
return view;
}
}
@laurencedawson
Copy link

I've just come across this, did you make any further progress?

@sumio
Copy link

sumio commented May 31, 2017

@fesago90
Your code saved my time. Thanks!
Would you please declare the license of your code?
I'd like to use your code to avoid memory leak.

@Kolyall
Copy link

Kolyall commented Jul 18, 2018

How to use the code?
I put my imageView to Pair

 FragmentActivity activity = getActivity();
               ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                Pair.create(imageView, "image"),
                Pair.create(addressTextView, "address")
             );
        Bundle bundle = options.toBundle();
        Intent intent = new Intent(activity,SecondActivity.class);
        ActivityCompat.startActivity(activity, intent , bundle);

but in this line bitmap is always null. And the method onCaptureSharedElementSnapshot is never called

@Kolyall
Copy link

Kolyall commented Jul 18, 2018

Seems in this line
https://gist.github.com/fesago90/ae7a56628c35e65ddaab#file-gistfile1-txt-L99
need to reverse

 imageView.setImageBitmap(bitmap);
                imageView.setScaleType(
ImageView.ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE)));

it should be like this:

imageView.setScaleType(
ImageView.ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE)));
imageView.setImageBitmap(bitmap);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment