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