[Full Version] 최신 AndroiodX 체크

[Full Version] 최신 AndroiodX 체크

"최신 AndroiodX 체크" 발표 중에 미처 발표하지 못한 내용이 포함된 풀 버전을 공개합니다.

354271902cd8ba2762d05b251dfa0f84?s=128

pluulove (노현석)

December 01, 2019
Tweet

Transcript

  1. ୭न AndroidX ୓௼ @pluu Full Version

  2. ୭न AndroidX ୓௼ Google Developer Experts for Android GDG Korea

    Android Organizer Noh HyeonSeok
  3. Index • Introduction AndroidX • Android Components • AndroidX in

    Android Dev Summit • Migration
  4. What is AndroidX?

  5. Question?! 1. AndroidXܳ ٜযࠌ׮? 2. Jetpackਸ ঌҊ੓׮? 3. Support Libraryо

    ӝরդ׮? 4. Android Architecture Components? 5. ੉ٜ੄ ର੉੼ਸ ঌҊ੓׮?
  6. Jetpack ۄ੉࠳۞ܻ, بҳ, о੉٘ ١੄ Ҋಿ૕ জਸ ࣚऔѱ ѐߊਸ ਤೠ

    ѐߊ ૑ஜ
  7. Jetpack == AndroidX - androidx.* ী ੓ח ۄ੉࠳۞ܻٜ - Jetpack

    Libraries - (ҳ) Support Libraries
  8. Jetpack Component AndroidX!!

  9. AndroidX Android ౱੉ Jetpack ղীࢲ ۄ੉࠳۞ܻܳ ѐߊ, పझ౟, ಁః૚, ߡ੹

    ҙܻ, ୹दೞחؘ ࢎਊೞח য়೑ࣗझ ೐۽ં౟ੑפ׮. https://developer.android.com/jetpack/androidx
  10. What's New in Android Support Library (Google I/O ’17)

  11. Source : https://www.youtube.com/watch?v=V6-roIeNUY0

  12. Source : https://www.youtube.com/watch?v=V6-roIeNUY0

  13. Source : https://www.youtube.com/watch?v=V6-roIeNUY0

  14. Updated packaging • Android java ࣗझܳ ಁః૑߹۽ ܻಂష݂ ▪ Android.<feature>.ClassName

    • Maven ▪ androidx.<feature>:<feature>-<sub-feature> ▪ ೙ਃೠ ӝמ߹ ߓನ • -v7, -v4 ಁః૑ݺ ઁѢ
  15. AndroidX Component

  16. https://developer.android.com/jetpack/androidx/versions/

  17. https://developer.android.com/jetpack/androidx/versions/

  18. https://developer.android.com/jetpack/androidx/versions/

  19. https://developer.android.com/jetpack/androidx/versions/

  20. AndroidX Component - Total 70ѐ (2019.11.29) - Support, UI -

    Benchmark, Migration … etc
  21. Activity & Fragment & Navigation - Activity 1.0.0(Stable) , 1.1.0-rc02(RC)

    - Fragment 1.1.0(Stable) , 1.2.0-rc02(RC) - Navigation 2.1.0(Stable) , 2.2.0-rc02(RC)
  22. class OldFragment : Fragment() { // Crazy fun backStart() {

    requireActivity().onBackPressed() } } җѢ Fragmentীࢲ onBackPressed // Crazy fun backStart() { requireActivity().onBackPressed() } // Safe override fun onAttach(context: Context) { super.onAttach(context) backListener = context as? BackListener backListener?.onBackPressed() }
  23. class MainFragment : Fragment() { private val dispatcher by lazy

    { requireActivity().onBackPressedDispatcher } private val backPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { // TODO } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) dispatcher.addCallback(this, backPressedCallback) } } Fragmentীࢲ onBackPressed ୊ܻ Back Pressed Flag
  24. // ComponentActivity.java public class ComponentActivity { private final OnBackPressedDispatcher mOnBackPressedDispatcher

    = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { // fallbackOnBackPressed ComponentActivity.super.onBackPressed(); } }); @Override @MainThread public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } } // OnBackPressedDispatcher.java public final class OnBackPressedDispatcher { @MainThread public void onBackPressed() { Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } } } ComponentActivity / BackPressedDispatcher ൒ܴ
  25. // ComponentActivity.java public class ComponentActivity { private final OnBackPressedDispatcher mOnBackPressedDispatcher

    = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { // fallbackOnBackPressed ComponentActivity.super.onBackPressed(); } }); @Override @MainThread public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } } // OnBackPressedDispatcher.java public final class OnBackPressedDispatcher { @MainThread public void onBackPressed() { Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } } } ComponentActivity / BackPressedDispatcher ൒ܴ
  26. // ComponentActivity.java public class ComponentActivity { private final OnBackPressedDispatcher mOnBackPressedDispatcher

    = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { // fallbackOnBackPressed ComponentActivity.super.onBackPressed(); } }); @Override @MainThread public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } } ComponentActivity / BackPressedDispatcher ൒ܴ // OnBackPressedDispatcher.java public final class OnBackPressedDispatcher { @MainThread public void onBackPressed() { Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } } }
  27. // ComponentActivity.java public class ComponentActivity { private final OnBackPressedDispatcher mOnBackPressedDispatcher

    = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { // fallbackOnBackPressed ComponentActivity.super.onBackPressed(); } }); @Override @MainThread public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } } // OnBackPressedDispatcher.java public final class OnBackPressedDispatcher { @MainThread public void onBackPressed() { Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } } } ComponentActivity / BackPressedDispatcher ൒ܴ
  28. // ComponentActivity.java public class ComponentActivity { private final OnBackPressedDispatcher mOnBackPressedDispatcher

    = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { // fallbackOnBackPressed ComponentActivity.super.onBackPressed(); } }); @Override @MainThread public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } } // OnBackPressedDispatcher.java public final class OnBackPressedDispatcher { @MainThread public void onBackPressed() { Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } } } ComponentActivity / BackPressedDispatcher ൒ܴ
  29. LiveData & ViewModel - Lifecycle 2.1.0(Stable) , 2.2.0-rc02(RC)

  30. ViewModel ୡӝച lifecycle-viewmodel private val viewModel by lazy { ViewModelProviders.of(this).get<MainViewModel>()

    } This constructor was deprecated in API level 1.1.0. This class should not be directly instantiated
  31. ViewModel ୡӝച lifecycle-viewmodel val vm: VM = ViewModelProvider(this, factory).get(VM::class.java) val

    vm: VM = ViewModelProvider(this).get(VM::class.java) public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); }
  32. None
  33. Support Coroutines in ViewModel After lifecycle-viewmodel-ktx 2.1.0 val ViewModel.viewModelScope: CoroutineScope

    get() { val scope: CoroutineScope? = this.getTag(JOB_KEY) if (scope != null) { return scope } return setTagIfAbsent(JOB_KEY, CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)) } To be continue…
  34. AndroidX in

  35. #AndroidDevSummit

  36. #AndroidDevSummit

  37. #AndroidDevSummit

  38. #AndroidDevSummit

  39. #AndroidDevSummit @Composable fun FilteredList(contacts: List<Contact>, filterText: String = "") {

    val state = +state { filterText } VerticalScroller { Column { TextField(filterText, onValueChange = { state.value = it }) contacts.filter { it.contains(state.value) }.forEach { Row { Image(it.photo) Text(it.name) } } } } }
  40. #AndroidDevSummit • Simplify • Fix what’s broken • No more

    cheating • Material + Animations • Compatibility Jetpack Compose
  41. #AndroidDevSummit Android Studio Live preview, Apply Changes Compose Compiler Plugin

    Code generation extensions kotlinc Upstream Kotlin compiler (1.4) Compose UI Foundation Standard layouts, interactions Compose UI Core Input, Measure, Layout, Drawing Compose Runtime Tree management, Effects Compose UI Material Surface, Buttons, Tabs, Themes Compose Build time (development host) Runtime (on device)
  42. #AndroidDevSummit Compose UI Foundation Standard layouts, interactions Compose UI Core

    Input, Measure, Layout, Drawing Compose UI Material Surface, Buttons, Tabs, Themes BUTTON Gestures, accessibility, & other internals
  43. Jetpack Compose • I/O 19, Unbundled • Announced Android Studio

    4.0 Canary 1 in Android Dev Summit • Last Release 0.1.0-dev02
  44. android/compose-samples https://github.com/android/compose-samples/tree/master/JetNews

  45. android/compose-samples https://github.com/android/compose-samples/tree/master/JetNews

  46. android/compose-samples https://github.com/android/compose-samples/tree/master/JetNews

  47. Compose Sample

  48. Compose Sample https://github.com/Pluu/JetpackCompose_Sample

  49. Merged ConstraintLayout in Compose Link : http://bit.ly/2rIbAao

  50. #AndroidDevSummit

  51. #AndroidDevSummit Using FragmentScenario @Test fun testEventFragment() { val scenario =

    launchFragmentInContainer<MyFragment>() onView(withId(R.id.refresh)).perform(click()) scenario.onFrament { fragment -> // Check that the fragment handled the click correctly. } }
  52. #AndroidDevSummit Using FragmentScenario @Test fun testEventMoveToCreatedFragment() { val scenario =

    launchFragmentInContainer<MyFragment>() scenario.moveToState(State.CREATED) } @Test fun testEventFragment() { val scenario = launchFragmentInContainer<MyFragment>() scenario.recreate() }
  53. #AndroidDevSummit Using FragmentFactory private class MyFactory() : FragmentFactory() { override

    fun instantiate( classLoader: ClassLoader, className: String ) = when (className) { MyFragment::class.java.name -> MyFragment(...) else -> super.instantiate(classLoader, className) } } override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = MyFactory() super.onCreate(savedInstanceState) }
  54. used add/replace

  55. None
  56. None
  57. None
  58. FragmentContainerView extends FrameLayout • Fragmentਊ Container ◦ AddView => IllegalStateException

    • <fragment> / <FrameLayout>ܳ ؀୓ • Z-index ޙઁ ೧Ѿ • 3о૑ ੘সਸ ૓೯ ◦ ࢜۽਍ Fragment ੋझఢझ ࢤࢿ ◦ Fragment.onInflate(Context, AttributeSet, Bundle) ഐ୹ ◦ FragmentTransactionਸ प೯ೞৈ FragmentManagerী ୶о
  59. FragmentContainerView <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" />

  60. FragmentContainerView <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/fragment_container_view" android:name="com.example.MyFragment" android:tag="my_tag" android:layout_width="match_parent" android:layout_height="match_parent" />

  61. // FirstFragment, SecondFragment parentFragmentManager .beginTransaction() .setCustomAnimations( R.anim.nav_enter, R.anim.nav_exit ) .replace(R.id.container,

    /**...*/ ) .addToBackStack(null) .commit() FrameLayout Not desired result
  62. FrameLayout FragmentContainerView

  63. ViewModel ୡӝച // activity-ktx val activityVM : ActivityViewModel by viewModels()

    // fragment-ktx val fragmentViewModel : MyViewModel by viewModels() val activityViewModel : MyViewModel by activityViewModels() // navigation-ktx val navGraphViewModel: MyViewModel by navGraphViewModels(R.id.main)
  64. #AndroidDevSummit

  65. ROOM #AndroidDevSummit • RxJava/Coroutines ૑ਗ • Raw ௪ܻ ૑ਗ •

    AndroidX ݃੉Ӓۨ੉࣌ • Full Text Search • Views • SQLiteী ؀ೠ ୶࢚ച ҅க ઁҕ • ஹ౵ੌ ఋ੐ী Query ୓௼ • Migration੉ ए਑ • పझ౟ೞӝ ए਑ • Last 2.2.2(Stable)
  66. #AndroidDevSummit Async queres Query Type Observable Read One-Shot Read /

    Write Lifecycle RxJava Coroutines LiveData Publisher, Observable, Flowable Flowable N/A Single, Maybe, Completale suspend fun New!
  67. Flow 101 - Kotlin coroutine primitive - Asynchronous - Cold

    stream • transform stream (e.g. map, filter) • consume data (e.g. collect, single, toList)
  68. Flow Example fun getDogsToPet(limit: Int = -1): Flow<Dog> = flow

    { var i = 0 while (limit < 0 || i > limit) { emit(getRandomDog()) i++ } }
  69. Flow Example https://twitter.com/FMuntenescu/status/1186484362327384064

  70. Pre-packaged databases #AndroidDevSummit

  71. ୡӝ DB ؘ੉ఠ ࢸ஖ (җѢ) 1. Database ৌӝ 2. Schema

    Ѩૐ 3. Database File ਫ਼Ә 4. Thread زӝച 5. Content ࠂࢎ 6. Database ײӝ #AndroidDevSummit
  72. #AndroidDevSummit Room.databaseBuilder(appContext, TestDatabase.class, "Sample.db") .createFromFile(File("mypath")) .build() Room.databaseBuilder(appContext, TestDatabase.class, "Sample.db") .createFromAsset("database/myapp.db")

    .build() New! New!
  73. Definition Relations - One-to-One - Many-to-Many #AndroidDevSummit

  74. One-to-One Example

  75. One-to-Many Example

  76. #AndroidDevSummit

  77. #AndroidDevSummit

  78. #AndroidDevSummit Coroutines

  79. #AndroidDevSummit • Easy to get off main thread • Minimal

    boilerplate • Structured concurrency = managed jobs Coroutines ੢੼
  80. #AndroidDevSummit ViewModel class MainActivityViewModel : ViewModel { init { viewModelScope.launch

    { // start } } }
  81. #AndroidDevSummit class MyActivity : Activity { override fun onCreate(state: Bundle?)

    { super.onCreate(state) lifecycleScope.launch { // Run } lifecycleScope.launchWhenResumed { // Run } } } Activities & Fragments lifecycleScope.launchWhenResumed { // Run }
  82. #AndroidDevSummit ViewModel + LiveData class MainActivityViewModel : ViewModel { private

    val _result = MutableLiveData<String>() val result = LiveData<String> = _result init { viewModelScope.launch { val computationResult = doComputation() _result.value = computationResult } } }
  83. #AndroidDevSummit liveData coroutine builder class MyViewModel { val result =

    liveData { emit(doComputation()) } } After lifecycle 2.2 liveData(Dispatchers.IO) { emit(LOADING.STRING) emitSource(dataSource.fetchWeather()) } 1 2 LiveData
  84. #AndroidDevSummit After lifecycle 2.2 Multiple values with LiveData

  85. #AndroidDevSummit After lifecycle 2.2 Streams with Flow

  86. emit N Values val currentWeather: LiveData<String> = dataSource.fetchWeather() LiveData →

    LiveData Flow → LiveData val currentWeatherFlow: LiveData<String> = liveData { dataSource.fetchWeatherFlow().collect { emit(it) } }
  87. emit N Values LiveData → LiveData Flow → LiveData val

    currentWeather: LiveData<String> = dataSource.fetchWeather() val currentWeatherFlow: LiveData<String> = dataSource.fetchWeatherFlow().asLiveData()
  88. emit 1 + emit N Values val currentWeather: LiveData<String> =

    liveData { emit(LOADING_STRING) emitSource(dataSource.fetchWeather()) } LiveData → LiveData Flow → LiveData val currentWeatherFlow: LiveData<String> = liveData { emit(LOADING_STRING) emitSource( dataSource.fetchWeatherFlow().asLiveData() ) }
  89. emit 1 + emit N Values val currentWeather: LiveData<String> =

    liveData { emit(LOADING_STRING) emitSource(dataSource.fetchWeather()) } LiveData → LiveData Flow → LiveData val currentWeatherFlow: LiveData<String> = dataSource.fetchWeatherFlow() .onStart { emit(LOADING_STRING) } .asLiveData()
  90. Transformation val currentWeather: LiveData<String> = dataSource.fetchWeather().map { // Run }

    LiveData → LiveData
  91. Suspend transformation val currentWeather: LiveData<String> = dataSource.fetchWeather().switchMap { liveData {

    emit(heavyTransformation(it)) } } LiveData → LiveData
  92. Suspend transformation val currentWeather: LiveData<String> = dataSource.fetchWeather().switchMap { liveData {

    emit(heavyTransformation(it)) } } LiveData → LiveData val currentWeatherFlow: LiveData<String> = dataSource.fetchWeatherFlow() .map { heavyTransformation(it) } .asLiveData() } Flow → LiveData
  93. #AndroidDevSummit

  94. CameraX - 1.0.0-alpha06 (Alpha)

  95. Android Dev Summit Focus +{API} HDR Capabilities Stability Extension

  96. #AndroidDevSummit +{API} New Capabilities • Tap to focus • Zoom

    control • Device rotation info • Flash availability • And a lot more!
  97. #AndroidDevSummit Focus Pinch Zoom Zoom Slider

  98. #AndroidDevSummit

  99. #AndroidDevSummit HDR Extensions • Expanding footprint with additional manufactures •

    Two lines of code enables Extensions across all of them!
  100. #AndroidDevSummit

  101. #AndroidDevSummit // Set up use case // Step 1. Config

    val imageCapture = ImageCaptureConfig.Builder() .setTargetResolution(Size(600, 800)) .build() // Step 2. Bind CameraX.bindToLifecycle(this, imageCapture) // Step 3. Act imageCapture.takePicture(...)
  102. CameraXView <androidx.camera.view.CameraView android:id="@+id/view_camera" android:layout_width="match_parent" android:layout_height="match_parent" /> CameraX#bindToLifecycle(LifecycleOwner) CameraView#takePicture(...) CameraView#startRecording(...) CameraView#stopRecording()

    CameraX.unbindAll()
  103. #AndroidDevSummit Beta 2019֙ 12ਘ ৘੿!! • Stable API • Higher

    code quality • Read for production
  104. #AndroidDevSummit

  105. Release - ConstraintLayout 2.0.0-beta3 - Android Studio 4.0 Canary 1

  106. None
  107. None
  108. None
  109. #AndroidDevSummit

  110. What is benchmarking? - ௏٘ ࢿמ ஏ੿ - ஏ੿ػ Ѿҗ۽

    ѐࢶ ߈৔ - ੹୓ ೐۽Ӓ۔ प೯ Improving App Performance with Benchmarking (Google I/O ’19) Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc
  111. Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc Benchmark @Test fun myFirstBenchmark() { val worker

    = TestListenableWorkerBuilder<MyWorker>(context).build() val COUNT = 5 // Small iteration count val start = System.nanoTime() // Measuring immediately for (i in 0..COUNT) { worker.doWork() } // Includes outliers! val elapsed = (System.nanoTime() - start) Log.d("Benchmark", "Time taken was $elapsed ns") }
  112. Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc Benchmark @Test fun myFirstBenchmark() { val worker

    = TestListenableWorkerBuilder<MyWorker>(context).build() val COUNT = 5 // Small iteration count val start = System.nanoTime() // Measuring immediately for (i in 0..COUNT) { worker.doWork() } // Includes outliers! val elapsed = (System.nanoTime() - start) Log.d("Benchmark", "Time taken was $elapsed ns") }
  113. Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc Benchmark @Test fun myFirstBenchmark() { val worker

    = TestListenableWorkerBuilder<MyWorker>(context).build() val COUNT = 5 // Small iteration count val start = System.nanoTime() // Measuring immediately for (i in 0..COUNT) { worker.doWork() } // Includes outliers! val elapsed = (System.nanoTime() - start) Log.d("Benchmark", "Time taken was $elapsed ns") }
  114. Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc Benchmark @get:Rule val benchmarkRule = BenchmarkRule() @Test

    fun myFirstBenchmark() { val worker = TestListenableWorkerBuilder<MyWorker>(context).build() val COUNT = 5 // Small iteration count val start = System.nanoTime() // Measuring immediately for (i in 0..COUNT) { worker.doWork() } // Includes outliers! val elapsed = (System.nanoTime() - start) Log.d("Benchmark", "Time taken was $elapsed ns") }
  115. Source : https://www.youtube.com/watch?v=ZffMCJdA5Qc Benchmark @get:Rule val benchmarkRule = BenchmarkRule() @Test

    fun myFirstBenchmark() { val worker = TestListenableWorkerBuilder<MyWorker>(context).build() benchmarkRule.measureRepeated { worker.doWork() } }
  116. RecyclerView Benchmark https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt

  117. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  118. @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule = BenchmarkRule()

    @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt RecyclerView Benchmark
  119. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  120. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  121. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  122. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  123. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt
  124. RecyclerView Benchmark @get:Rule val activityRule = ActivityTestRule(MainActivity::class.java) @get:Rule val benchmarkRule

    = BenchmarkRule() @UiThreadTest @Test fun simpleScroll() { val recyclerView = activityRule.activity.recyclerView benchmarkRule.measureRepeated { val heightOfLastItem = recyclerView.getLastChild().height recyclerView.scrollBy(0, heightOfLastItem) } } https://github.com/android/performance-samples/blob/master/BenchmarkSample/benchmark/ src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt Without Time runWithTimingDisabled(…)
  125. RecyclerView Benchmark

  126. Migration to AndroidX

  127. CardView vs CardView Support (28.0.0-alpha01) AndroidX (1.0.0) 45 Removals, 44

    Additions - JavaDoc : 38 lines - Package/Import : 5 lines - Empty Line : 1 lines Package name݅ ׮ܴ
  128. Fragment 28.0.0-alpha01 vs 1.2.0-rc01 419 Removals, 746 Additions

  129. җѢ ߡ੹җ੄ ࠺Ү ഝߊೞѱ সؘ੉౟о ੌযաח Component੄ ӝמ਷ ௼ѱ ର੉դ׮.

  130. I/O '18 Announce Migration Support Library => AndroidX

  131. https://developer.android.com/topic/libraries/support-library/revisions

  132. Better package management ؕ஖ ௾ Library ܻ࠙ => ؊ ࡅܲ

    ܾܻૉ - Google Play Services - Firebase - ButterKnife - Mockito2 - SQL Delight - New libraries
  133. FIRST backup backup backup backup backup backup backup backup backup

    backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup backup
  134. #AndroidDevSummit

  135. Not Support Code generation libraries

  136. Migration • Menu Bar Refactor > Migrate to AndroidX ࢶఖ

    • External Librariesী AndroidX ޷֢୹द Opt 1. Gradle Sync Opt 2. Invalidate Caches / Restart • 100% ߸ജ੉ উؼ ࣻ ੓ਵ޲۽ ѐੋ੸ਵ۽ ࣻز੉ উ੿੸
  137. Targeting API level 28 or lower dependencies { ... implementation

    'com.android.support:appcompat-v7:28.0.0' implementation 'android.arch.lifecycle:extensions:1.1.1' ... }
  138. Jetifier Disable Jetifier = false / AndroidX = true

  139. Targeting API level 29+ dependencies { ... implementation 'com.android.support:appcompat-v7:28.0.0' implementation

    'android.arch.lifecycle:extensions:1.1.1' ... }
  140. gradle.properties # AndroidX package structure to make it clearer which

    packages are bundled with the # Android operating system, and which are packaged with your app's APK android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=tru https://developer.android.com/studio/command-line/jetifier
  141. Jetifier Disable Jetifier Enable AppCompat

  142. Jetifier Disable Jetifier Enable 3rd-party Library

  143. Jetifier AndroidX ಁః૑ܳ ࢎਊೡ ࣻ ੓ب۾ Support Libraryܳ ݃੉Ӓۨ੉࣌ Migration

    ߑߨ • Android Studio ղ੄ Bundle۽ ػ Plugin ࢎਊ • ૒੽ ݃੉Ӓۨ੉࣌ https://developer.android.com/studio/command-line/jetifier
  144. Jetifier Transform-Rule https://android.googlesource.com/platform/frameworks/support/+/androidx- master-dev/jetifier/jetifier/core/src/main/resources/default.config default.config ౵ੌ ղࠗী ࢎ੹ ੿੄ ػ

    Migration Rule
  145. Not Support - Version configuration files - Proguard files

  146. Migration to AndroidX • Support Libraryח Deprecate • ঱ઃо ೧ঠೡ

    ੘স਷ ؊ ੉࢚ ইפ׮ • Release Android 10 (2019.09.03) • ࢲ࠺झ੄ ઱ਃ ױ݈੄ Android 10 সؘ੉౟ दӝ ୓௼
  147. #AndroidDevSummit goo.gle/plaid-androidx-migration

  148. Stable Activity AppCompat Lifecycle Navigation Room Work Autofill Benchmark Biometric

    Coordinator Layout Fragment Lifecycle ViewModel-SavedState Navigation RecyclerView ViewPager2 ConstraintLayout RC Beta Alpha Ads Browser Camera Car Compose Security
  149. Watch the talks and learn more! Android Dev Summit 2019

  150. Watch the talks and learn more! Android Dev Summit 2019

    END