Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How may we optimize (cpu & ram) this android custom splash animation?

I developed a custom animation for my Splash Screen activity :

=> Here is an animation that show what is happening :

enter image description here

Of course my real app :

  • is with different pictures (fullhd)
  • is a bit slower compare to the GIF: 3s for 60 intermediate screens.

My designer provided me 60 png files.

=> One example to illustrate :

enter image description here

My target is:

  1. start from a central logo (here with SO) with a bottom picture (Apple)
  2. run a morphing animation
  3. end at the screen like the home page of the app

To run this, I have one Multilayer layout for the SpashScreenActivity with:

  • BackGround (invisible) : the layout of the homePage (MainActivity)
  • MiddleGround : with the ImageView of the Apple that is replaced by the Droid and the bottomBar that grow
  • FrontGround : the logo in an ImageView with its slogan in a TextView

Here is the xml code for the SpashScreen Layout :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/fl_logo_top_marge_hidden"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:visibility="invisible"
            android:background="@color/colorPrimary" />

        <include
            android:visibility="invisible"
            android:id="@+id/l_logo_activate_hidden"
            layout="@layout/part_logo_activate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:visibility="invisible"
            android:id="@+id/fl_logo_bottom_marge_hidden"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorPrimary" />

        <fr.millezimsolutions.app.splashanimation.SquareAspectWidthBasedImageView
            android:visibility="invisible"
            android:id="@+id/iv_home_hidden"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitXY"
            android:src="@drawable/p_log_android" />

        <FrameLayout
            android:visibility="invisible"
            android:id="@+id/fl_bar_hidden"
            android:layout_width="match_parent"
            android:layout_height="@dimen/start_degustation_bar_height"
            android:background="@color/colorAccent"
            android:gravity="bottom" />
    </LinearLayout>


    <LinearLayout
        android:id="@+id/fl_middle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:background="@color/colorPrimary"
        android:gravity="bottom"
        android:orientation="vertical">

        <fr.millezimsolutions.app.splashanimation.FitXCropTopImageView
            android:id="@+id/iv_slogan"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorTransparent"
            android:scaleType="fitStart"
            android:src="@drawable/p_log_apple" />

        <FrameLayout
            android:id="@+id/fl_logo_bottom_bar"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:background="@color/colorAccent"
            android:gravity="bottom" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/fl_front"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/fl_logo_top_layout"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="40"
            android:background="@color/colorPrimary" />

        <FrameLayout
            android:id="@+id/fl_logo_top_marge"
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@color/colorTransparent" />

        <include
            android:id="@+id/l_logo_activate"
            layout="@layout/part_logo_activate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:id="@+id/fl_logo_bottom_marge"
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@color/colorTransparent" />

        <FrameLayout
            android:id="@+id/fl_logo_bottom_layout"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="40"
            android:background="@color/colorTransparent" />
    </LinearLayout>
</RelativeLayout>

2 The xml code for the top of the layout (via include)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorTransparent"
    android:gravity="bottom"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fl_home_marginTop"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <ImageView
        android:id="@+id/iv_millezimuLogo"
        android:layout_width="wrap_content"
        android:layout_height="64dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="@dimen/marge"
        android:layout_marginRight="@dimen/marge"
        android:src="@drawable/p_log_so" />

    <TextView
        android:id="@+id/tv_slogan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="@dimen/marge_small"
        android:layout_marginTop="@dimen/marge_small_border"
        android:gravity="center"
        android:hint=""
        android:text="Bonjour"
        android:textColor="@color/colorAccent"
        android:textSize="20sp" />

    <ImageView
        android:id="@+id/iv_sponsorLogo"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="@dimen/marge"
        android:layout_marginRight="@dimen/marge"
        android:src="@drawable/p_log_so"
        android:visibility="gone" />

    <TextView
        android:id="@+id/tv_sponsorLogo"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="@dimen/marge"
        android:layout_marginRight="@dimen/marge"
        android:gravity="center"
        android:textColor="@color/colorAccent"
        android:textSize="20sp"
        android:visibility="gone" />

    <FrameLayout
        android:id="@+id/fl_home_marginBottom"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

3 Here is the code of the Activity.

 import android.content.Intent; 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;

 public class SplashScreenActivity extends AppCompatActivity {

    // Splash screen timer
    private static int SPLASH_TIME_OUT = 3000;
    private int finalTopMarge, finalBottomMarge, topMargeDec, bottomMargeInc;
    long currentTimeStamp;

    private int[] mSplashAnimFrames = {R.drawable.p_wave_spashscreen_00, R.drawable.p_wave_spashscreen_01, R.drawable.p_wave_spashscreen_02, R.drawable.p_wave_spashscreen_03, R.drawable.p_wave_spashscreen_04, R.drawable.p_wave_spashscreen_05, R.drawable.p_wave_spashscreen_06, R.drawable.p_wave_spashscreen_07, R.drawable.p_wave_spashscreen_08, R.drawable.p_wave_spashscreen_09,
            R.drawable.p_wave_spashscreen_10, R.drawable.p_wave_spashscreen_11, R.drawable.p_wave_spashscreen_12, R.drawable.p_wave_spashscreen_13, R.drawable.p_wave_spashscreen_14, R.drawable.p_wave_spashscreen_15, R.drawable.p_wave_spashscreen_16, R.drawable.p_wave_spashscreen_17, R.drawable.p_wave_spashscreen_18, R.drawable.p_wave_spashscreen_19,
            R.drawable.p_wave_spashscreen_20, R.drawable.p_wave_spashscreen_21, R.drawable.p_wave_spashscreen_22, R.drawable.p_wave_spashscreen_23, R.drawable.p_wave_spashscreen_24, R.drawable.p_wave_spashscreen_25, R.drawable.p_wave_spashscreen_26, R.drawable.p_wave_spashscreen_27, R.drawable.p_wave_spashscreen_28, R.drawable.p_wave_spashscreen_29,
            R.drawable.p_wave_spashscreen_30, R.drawable.p_wave_spashscreen_31, R.drawable.p_wave_spashscreen_32, R.drawable.p_wave_spashscreen_33, R.drawable.p_wave_spashscreen_34, R.drawable.p_wave_spashscreen_35, R.drawable.p_wave_spashscreen_36, R.drawable.p_wave_spashscreen_37, R.drawable.p_wave_spashscreen_38, R.drawable.p_wave_spashscreen_39,
            R.drawable.p_wave_spashscreen_40, R.drawable.p_wave_spashscreen_41, R.drawable.p_wave_spashscreen_42, R.drawable.p_wave_spashscreen_43, R.drawable.p_wave_spashscreen_44, R.drawable.p_wave_spashscreen_45, R.drawable.p_wave_spashscreen_46, R.drawable.p_wave_spashscreen_47, R.drawable.p_wave_spashscreen_48, R.drawable.p_wave_spashscreen_49,
            R.drawable.p_wave_spashscreen_50, R.drawable.p_wave_spashscreen_51, R.drawable.p_wave_spashscreen_52, R.drawable.p_wave_spashscreen_53, R.drawable.p_wave_spashscreen_54, R.drawable.p_wave_spashscreen_55, R.drawable.p_wave_spashscreen_56, R.drawable.p_wave_spashscreen_57, R.drawable.p_wave_spashscreen_58, R.drawable.p_wave_spashscreen_59};


    private final int C_STOP = 120, C_MOVE = 40, C_BAR = 80;
    private int bottomBarRatio;
    private ImageView finalImageView;
    private int targetWidth, targetHeight;
    private Rect mImageViewRect;
    private Paint paint;
    private Bitmap original;
    private Bitmap result;
    private boolean setupOk = false;
    private ImageView mImageView;
    private Bitmap mask;
    private FrameLayout ltm;
    private FrameLayout lbm;
    private FrameLayout lbb;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_screen);

        // Indique que l'ecran est full Screen
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        ImageManager.create(this);

    }


    @Override
    protected void onResume() {
        super.onResume();
        int delay = SPLASH_TIME_OUT / C_STOP;
        bottomBarRatio = getResources().getDimensionPixelSize(R.dimen.bar_nav_height) / (C_STOP - C_BAR);
        runCycle(0, delay);
    }


    private void logStamp() {
        long oldTimeStamp = currentTimeStamp;
        currentTimeStamp = System.currentTimeMillis();
        long delay = currentTimeStamp - oldTimeStamp;
        Log.v("TIMESTAMP", String.valueOf(delay));
    }

    public void runCycle(final int cycle, final int delay) {
        if (BuildConfig.DEBUG)
            logStamp();

        Handler cyclic = new Handler();
        cyclic.postDelayed(new Runnable() {

            @Override
            public void run() {

                if (cycle >= C_STOP) {
                    closeActivity();
                } else {
                    runCycle(cycle + 1, delay);

                    if (cycle >= C_MOVE) {
                        // Copy des hauteurs pour les marges
                        initFinalLogoMargeHeight();

                        // Decroissance du poid de layout superieur
                        MoveUpLogo();

                        // bouger la bar
                        if (cycle >= C_BAR) {
                            updateBottomBar(cycle - C_BAR);
                        }
                        findViewById(R.id.fl_front).requestLayout();
                    }

                    if (setupFinalView()) {
                        if ((cycle % 2) == 0)
                            updateImageViewLight(cycle / 2);
                    }
                }
            }

        }, delay);
    }


    private boolean setupFinalView() {
        if (!setupOk) {
            finalImageView = (ImageView) findViewById(R.id.iv_home_hidden);
            targetWidth = finalImageView.getWidth();
            targetHeight = finalImageView.getHeight();
            mImageViewRect = new Rect(0, 0, finalImageView.getWidth(), finalImageView.getHeight());
            mImageView = (ImageView) findViewById(R.id.iv_slogan);
            mImageView.setBackgroundResource(R.drawable.p_log_apple);

            paint = new Paint(Paint.ANTI_ALIAS_FLAG);

            ltm = (FrameLayout) findViewById(R.id.fl_logo_top_marge);
            lbm = (FrameLayout) findViewById(R.id.fl_logo_bottom_marge);
            lbb = ((FrameLayout) findViewById(R.id.fl_logo_bottom_bar));


            if (targetWidth > 0 && targetHeight > 0) {
                original = ImageManager.decodeSampledBitmapFromResource(getResources(), R.drawable.p_log_android, targetWidth, targetHeight);
                result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_4444);
                setupOk = true;
            }
        }
        return setupOk;
    }

    private void MoveUpLogo() {
        ViewGroup.LayoutParams ltmp = ltm.getLayoutParams();
        ltmp.height -= topMargeDec;

        ViewGroup.LayoutParams lbmp = lbm.getLayoutParams();
        lbmp.height += bottomMargeInc;
    }


    private void initFinalLogoMargeHeight() {
        if (finalBottomMarge == 0) {
            finalTopMarge = findViewById(R.id.fl_logo_top_marge_hidden).getHeight();
            topMargeDec = (findViewById(R.id.fl_logo_top_marge).getHeight() - finalTopMarge) / C_BAR;
            finalBottomMarge = findViewById(R.id.fl_logo_bottom_marge_hidden).getHeight() + findViewById(R.id.fl_bar_hidden).getHeight() + findViewById(R.id.iv_home_hidden).getHeight();
            bottomMargeInc = (finalBottomMarge - findViewById(R.id.fl_logo_bottom_marge).getHeight()) / C_BAR;
        }
    }

    private void updateBottomBar(int cycle) {
        LinearLayout.LayoutParams lbbp = (LinearLayout.LayoutParams) lbb.getLayoutParams();
        lbbp.height = cycle * bottomBarRatio;
        lbb.setLayoutParams(lbbp);
    }


    private void closeActivity() {
        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        Intent i = new Intent(SplashScreenActivity.this, MainActivity.class);
        startActivity(i);
        finish();
        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
    }

    private int getNext(int index) {
        if (index < (mSplashAnimFrames.length - 1))
            index++;
        else
            index = mSplashAnimFrames.length - 1;
        return mSplashAnimFrames[index];
    }


    public void updateImageViewLight(int index) {

        mask = ImageManager.decodeSampledBitmapFromResource(getResources(), getNext(index), targetWidth, targetHeight);
        Canvas mCanvas = new Canvas(result);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mCanvas.drawBitmap(original, null, mImageViewRect, null);
        mCanvas.drawBitmap(mask, null, mImageViewRect, paint);
        paint.setXfermode(null);
        mImageView.setImageBitmap(result);
    }

}

4 And the code of the ImageManager for understanding (I use UIL)

public class ImageManager {


    private static Context context;

    public static ImageLoader getImageLoader() {
        return ImageLoader.getInstance();
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.outWidth = reqWidth;
        options.outHeight = reqHeight;
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return getResourceImageForCanvas(resId, new ImageSize(reqWidth, reqHeight));
    }

    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }



    public static Bitmap getResourceImageForCanvas(int bitmapResourceId, ImageSize targetImageSize) {
        DisplayImageOptions options = new DisplayImageOptions.Builder().bitmapConfig(Bitmap.Config.RGB_565).build();
        return getImageLoader().loadImageSync("drawable://" + bitmapResourceId, targetImageSize, options);
//
    }

    public static void create(Context context) {
        try {
            ImageManager.context = context;
            initImageLoader();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static void initImageLoader() throws IOException {
        // Create global configuration and initialize ImageLoader with this
        // configuration

        BitmapFactory.Options opt = new BitmapFactory.Options();
        // opt.inScaled = false;
        opt.inSampleSize = 1;
        opt.inDither = true;
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPreferQualityOverSpeed = false;

        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()./* cacheInMemory(true). */cacheOnDisk(true).decodingOptions(opt).imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                .bitmapConfig(Bitmap.Config.RGB_565).build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context).defaultDisplayImageOptions(defaultOptions).memoryCacheSizePercentage(13).writeDebugLogs().build();
        ImageLoader.getInstance().init(config);
    }

}

STATUS:

The updateImageViewLight method may provably help other to deal with this kind of behavior (PortedDuff...) that wasn't easy to find.

The animation works fine on a powerful device, but often lag if the device or the app does something else.

I have tried to run this calculation in Async Task but it was less powerful than in the mainThread

QUESTIONS:

I'm looking for any educated advise on my implementation, which may help to improve :

  • memory consumption
  • CPU usage

But also :

  • potential leak
  • code readability
like image 935
Anthony Avatar asked Apr 01 '16 16:04

Anthony


1 Answers

Not yet fully answer, but it is a try, that need to be continued and commented.

First optimisation:

  • Create a custom view (here ImageView extension) for the wave, that will refresh on onDraw method
  • define const member as static final class members
  • as most at possible, avoid objects instance creation in onDraw (Canvas and Paint) as well as unnecessary object update

Here is the code of the CustomView that extends ImageView

    public class WaveFillingImageView extends ImageView {

    private final static int[] mSplashAnimFrames = {R.drawable.p_wave_spashscreen_00, R.drawable.p_wave_spashscreen_01, R.drawable.p_wave_spashscreen_02, R.drawable.p_wave_spashscreen_03, R.drawable.p_wave_spashscreen_04, R.drawable.p_wave_spashscreen_05, R.drawable.p_wave_spashscreen_06, R.drawable.p_wave_spashscreen_07, R.drawable.p_wave_spashscreen_08, R.drawable.p_wave_spashscreen_09,
            R.drawable.p_wave_spashscreen_10, R.drawable.p_wave_spashscreen_11, R.drawable.p_wave_spashscreen_12, R.drawable.p_wave_spashscreen_13, R.drawable.p_wave_spashscreen_14, R.drawable.p_wave_spashscreen_15, R.drawable.p_wave_spashscreen_16, R.drawable.p_wave_spashscreen_17, R.drawable.p_wave_spashscreen_18, R.drawable.p_wave_spashscreen_19,
            R.drawable.p_wave_spashscreen_20, R.drawable.p_wave_spashscreen_21, R.drawable.p_wave_spashscreen_22, R.drawable.p_wave_spashscreen_23, R.drawable.p_wave_spashscreen_24, R.drawable.p_wave_spashscreen_25, R.drawable.p_wave_spashscreen_26, R.drawable.p_wave_spashscreen_27, R.drawable.p_wave_spashscreen_28, R.drawable.p_wave_spashscreen_29,
            R.drawable.p_wave_spashscreen_30, R.drawable.p_wave_spashscreen_31, R.drawable.p_wave_spashscreen_32, R.drawable.p_wave_spashscreen_33, R.drawable.p_wave_spashscreen_34, R.drawable.p_wave_spashscreen_35, R.drawable.p_wave_spashscreen_36, R.drawable.p_wave_spashscreen_37, R.drawable.p_wave_spashscreen_38, R.drawable.p_wave_spashscreen_39,
            R.drawable.p_wave_spashscreen_40, R.drawable.p_wave_spashscreen_41, R.drawable.p_wave_spashscreen_42, R.drawable.p_wave_spashscreen_43, R.drawable.p_wave_spashscreen_44, R.drawable.p_wave_spashscreen_45, R.drawable.p_wave_spashscreen_46, R.drawable.p_wave_spashscreen_47, R.drawable.p_wave_spashscreen_48, R.drawable.p_wave_spashscreen_49,
            R.drawable.p_wave_spashscreen_50, R.drawable.p_wave_spashscreen_51, R.drawable.p_wave_spashscreen_52, R.drawable.p_wave_spashscreen_53, R.drawable.p_wave_spashscreen_54, R.drawable.p_wave_spashscreen_55, R.drawable.p_wave_spashscreen_56, R.drawable.p_wave_spashscreen_57, R.drawable.p_wave_spashscreen_58, R.drawable.p_wave_spashscreen_59};
    private Paint paint;
    private long nextDrawTimeStamp;
    private boolean init = false, isStarted = false;
    private Bitmap original, result;
    private Rect mImageViewRect;
    private int index = 0;
    private LogAndStat las;
    private Canvas mCanvas;
    private  final int timeTick = 50;

    public WaveFillingImageView(Context context) {
        super(context);
        init(context);
    }

    public WaveFillingImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public WaveFillingImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @DebugLog
    private void init(Context context) {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        las = new LogAndStat("View", mSplashAnimFrames.length);
    }

    public void start() {
        isStarted = true;
        nextDrawTimeStamp = System.currentTimeMillis();
        invalidate();
    }

    @DebugLog
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Before Layout
        if (getWidth() == 0 || getHeight() == 0)
            return;
        // Init variables
        if (!init) {
            las.logStamp("init onDraw");
            original = ImageManager.decodeSampledBitmapFromResourcewithUIL(getResources(), R.drawable.p_log_android, getWidth(), getHeight());
            result = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
            mCanvas = new Canvas(result);
            mImageViewRect = new Rect(0, 0, getWidth(), getHeight());
            init = true;
            las.logStamp("init onDraw");

        }
        // If tick reached for refresh
        if (System.currentTimeMillis() >= nextDrawTimeStamp) {
            nextDrawTimeStamp += timeTick;
            las.logStamp(index);
            Bitmap mask = ImageManager.decodeSampledBitmapFromResourcewithUIL(getResources(), getResourceForNextCycle(index), mImageViewRect.width(), mImageViewRect.height());
            mCanvas.drawBitmap(original, null, mImageViewRect, null);
            mCanvas.drawBitmap(mask, null, mImageViewRect, paint);
            canvas.drawBitmap(result, 0, 0, null);

            index++;
        }
        if (isStarted)
            // Invalidate during animation to call again on Draw
            if (index < mSplashAnimFrames.length) {
                las.logStamp("invalidate");
                invalidate();
            } else {
                las.logStats();
            }
    }

    @DebugLog
    private int getResourceForNextCycle(int index) {
        if (index < (mSplashAnimFrames.length - 1))
            index++;
        else
            index = mSplashAnimFrames.length - 1;
        return mSplashAnimFrames[index];
    }

    @DebugLog
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }
    }

Results:

  • Animation is smothered, and seems taking fewer resources. However it is completely unsynchronized with the layout animation. Need to do that. Any best practices ?
  • This is clearly the init step of onDraw method that take time at the first cycle
  • Working on temporary canvas to finally draw the canvas on the main view canvas improved a lot
like image 69
Anthony Avatar answered Sep 17 '22 12:09

Anthony