1 package com.airbnb.lottie; 2 3 import android.util.Log; 4 5 import androidx.collection.ArraySet; 6 import androidx.core.util.Pair; 7 8 import com.airbnb.lottie.utils.MeanCalculator; 9 10 import java.util.ArrayList; 11 import java.util.Collections; 12 import java.util.Comparator; 13 import java.util.HashMap; 14 import java.util.List; 15 import java.util.Map; 16 import java.util.Set; 17 18 public class PerformanceTracker { 19 20 public interface FrameListener { onFrameRendered(float renderTimeMs)21 void onFrameRendered(float renderTimeMs); 22 } 23 24 private boolean enabled = false; 25 private final Set<FrameListener> frameListeners = new ArraySet<>(); 26 private final Map<String, MeanCalculator> layerRenderTimes = new HashMap<>(); 27 private final Comparator<Pair<String, Float>> floatComparator = 28 new Comparator<Pair<String, Float>>() { 29 @Override public int compare(Pair<String, Float> o1, Pair<String, Float> o2) { 30 float r1 = o1.second; 31 float r2 = o2.second; 32 if (r2 > r1) { 33 return 1; 34 } else if (r1 > r2) { 35 return -1; 36 } 37 return 0; 38 } 39 }; 40 setEnabled(boolean enabled)41 void setEnabled(boolean enabled) { 42 this.enabled = enabled; 43 } 44 recordRenderTime(String layerName, float millis)45 public void recordRenderTime(String layerName, float millis) { 46 if (!enabled) { 47 return; 48 } 49 MeanCalculator meanCalculator = layerRenderTimes.get(layerName); 50 if (meanCalculator == null) { 51 meanCalculator = new MeanCalculator(); 52 layerRenderTimes.put(layerName, meanCalculator); 53 } 54 meanCalculator.add(millis); 55 56 if (layerName.equals("__container")) { 57 for (FrameListener listener : frameListeners) { 58 listener.onFrameRendered(millis); 59 } 60 } 61 } 62 addFrameListener(FrameListener frameListener)63 public void addFrameListener(FrameListener frameListener) { 64 frameListeners.add(frameListener); 65 } 66 removeFrameListener(FrameListener frameListener)67 @SuppressWarnings("unused") public void removeFrameListener(FrameListener frameListener) { 68 frameListeners.remove(frameListener); 69 } 70 clearRenderTimes()71 public void clearRenderTimes() { 72 layerRenderTimes.clear(); 73 } 74 logRenderTimes()75 public void logRenderTimes() { 76 if (!enabled) { 77 return; 78 } 79 List<Pair<String, Float>> sortedRenderTimes = getSortedRenderTimes(); 80 Log.d(L.TAG, "Render times:"); 81 for (int i = 0; i < sortedRenderTimes.size(); i++) { 82 Pair<String, Float> layer = sortedRenderTimes.get(i); 83 Log.d(L.TAG, String.format("\t\t%30s:%.2f", layer.first, layer.second)); 84 } 85 } 86 getSortedRenderTimes()87 public List<Pair<String, Float>> getSortedRenderTimes() { 88 if (!enabled) { 89 return Collections.emptyList(); 90 } 91 List<Pair<String, Float>> sortedRenderTimes = new ArrayList<>(layerRenderTimes.size()); 92 for (Map.Entry<String, MeanCalculator> e : layerRenderTimes.entrySet()) { 93 sortedRenderTimes.add(new Pair<>(e.getKey(), e.getValue().getMean())); 94 } 95 Collections.sort(sortedRenderTimes, floatComparator); 96 return sortedRenderTimes; 97 } 98 } 99