Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Make your Android app fast again

Make your Android app fast again

Преждевременная оптимизация – корень всех зол. Но иногда оптимизация перестает быть преждевременной, и такие ситуации могут завести разработчика в тупик. Мы поговорим об общих проблемах перформанса, о том, как приступить к задаче оптимизации вашего приложения, а самое главное – разберем большое количество конкретных советов, которые вы можете использовать для отладки производительности, ускорения запуска приложения и увеличения fps.

Artur Vasilov

November 15, 2017
Tweet

More Decks by Artur Vasilov

Other Decks in Programming

Transcript

  1. 3

  2. My awesome feature #27 public class App extends Application {

    @Override public void onCreate() { super.onCreate(); // ... Lib25.init(this); Lib26.init(this); Lib27.init(this); } }
  3. My awesome feature #27 appComponent = DaggerAppComponent.builder() // ... .featureModule25(new

    FeatureModule25()) .featureModule26(new FeatureModule26()) .featureModule27(new FeatureModule27()) .build();
  4. Metrics public class App extends Application { @Override public void

    onCreate() { super.onCreate(); // ... Lib25.init(this); Lib26.init(this); Lib27.init(this); } } Синий цвет не правильный › Your eyes
  5. Metrics long start = System.nanoTime(); someLongRunningMethodToMeasure(); long time = System.nanoTime()

    - start; Log.i("Profiling", "Execution time = " + time / 1_000_000 + "ms"); Синий цвет не правильный › Your eyes › System#nanoTime
  6. Metrics › Your eyes › System#nanoTime › Users statistics ›

    Systrace › Other tools: Android Studio 3.0 Profilers, Traceview, … 19
  7. Stub Lib public static void init(@NonNull Context context) { PerformanceUtils.sleepRandom(100,

    200); initialized = true; } public static void start() { if (!initialized) { throw new IllegalStateException("You have to initialize Lib6 first"); } App.getAppComponent().getLib6Class().doSomeAction(); }
  8. “Heavy” class public class Lib6Class { public Lib6Class() { PerformanceUtils.sleepRandom(40,

    100); } public void doSomeAction() { PerformanceUtils.logMessage("Do some action called from Lib6Class"); } }
  9. More traces public static void init(@NonNull Context context) { Trace.beginSection("Init

    Lib1"); PerformanceUtils.sleepRandom(100, 200); initialized = true; Trace.endSection(); }
  10. Steps 0. No I/O work in Main Thread 1. Run

    systrace 2. Asynchronous initialization 37
  11. Asynchronous initialization @Override public void onCreate() { super.onCreate(); executorService =

    Executors.newFixedThreadPool(3); executorService.execute(() -> Lib5.init(this)); executorService.execute(() -> Lib6.init(this)); // ... executorService.execute(() -> Lib10.init(this)); Trace.beginSection("Init libraries"); Lib1.init(this); // ... Lib4.init(this); Trace.endSection(); }
  12. Steps 0. No I/O work in Main Thread 1. Run

    systrace 2. Asynchronous initialization 3. Warm up 40
  13. Steps 0. No I/O work in Main Thread 1. Run

    systrace 2. Asynchronous initialization 3. Warm up 4. Don’t break concurrency 42
  14. Concurrency problem public static void init(@NonNull Context context) { PerformanceUtils.sleepRandom(100,

    200); initialized = true; } public static void start() { if (!initialized) { throw new IllegalStateException("You have to initialize Lib1 first"); } App.getAppComponent().getLib1Class().doSomeAction(); }
  15. Steps 0. No I/O work in Main Thread 1. Run

    systrace 2. Asynchronous initialization 3. Warm up 4. Don’t break concurrency 5. Provider<T> / Lazy<T> 45
  16. Dependencies @Module(includes = {Module1.class, Module8.class}) public class DependentModule { @NonNull

    @Singleton @Provides DependentClass provideDependentClass(@NonNull Lib1Class lib1Class, @NonNull Lib8Class lib8Class) { return new DependentClass(lib1Class, lib8Class); } }
  17. Provider<T> @Module(includes = {Module1.class, Module8.class}) public class DependentModule { @NonNull

    @Singleton @Provides DependentClass provideDependentClass(@NonNull Provider<Lib1Class> lib1ClassProvider, @NonNull Provider<Lib8Class> lib8ClassProvider) { return new DependentClass(lib1ClassProvider, lib8ClassProvider); } }
  18. Lazy<T> @Module(includes = {Module1.class, Module8.class}) public class DependentModule { @NonNull

    @Singleton @Provides DependentClass provideDependentClass(@NonNull Lazy<Lib1Class> lib1ClassLazy, @NonNull Lazy<Lib8Class> lib8ClassLazy) { return new DependentClass(lib1ClassLazy, lib8ClassLazy); } }
  19. Steps 1. Run systrace 2. Asynchronous initialization 3. Warm up

    4. Don’t break concurrency 5. Provider<T> / Lazy<T> 6. Experiments 49
  20. Steps 2. Asynchronous initialization 3. Warm up 4. Don’t break

    concurrency 5. Provider<T> / Lazy<T> 6. Experiments 7. Look at your systrace again and optimize everything you can 51
  21. And finally 1. Optimize your app 2. Go to step

    1 64 Image source: http://roonby.com/2015/11/10/5-ways-to-improve-your-android-performance/
  22. [email protected] Make your Android app fast again Artur Vasilov Android

    developer ArturVasilov ArturVasilov VasilovArtur