Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

What's new in Jetpack Google IO 22

What's new in Jetpack Google IO 22

GDSC HUFS Google I/O 22 Extended 발표자료 입니다.

Jaesung Lee

August 15, 2022
Tweet

More Decks by Jaesung Lee

Other Decks in Programming

Transcript

  1. Activity AppCompat Camera Compose DataBinding Fragment Hilt LifeCycle MaterialDesignComponent Navigation

    Paging Room Test WorkManager WindowManager DataStore Prerference BenchMark Core Emoji2 RecyclerView ConstraintLayout Media Macrobenchmark JankStats SavedState BaselineProfiles https://developer.android.com/jetpack/androidx/explorer?case=all
  2. Rewritten from Java to Kotlin Support for Kotlin! Google I/O

    2017 https://android-developers.googleblog.com/2017/05/android-announces-support-for-kotlin.html
  3. TimeLine 2017 Kotlin 2018 KTX Android Jetpack 2019 BenchMark Kotlin

    first! Official Language Many New Jetpack APIs and features will be offered first in Kotlin!
  4. TimeLine 2017 Kotlin 2018 KTX Android Jetpack 2019 BenchMark Kotlin

    first! Official Language 2020 Paging3 Window DataStore https://developer.android.com/jetpack/androidx/versions/alpha-channel#august_11_2020 Compose
  5. TimeLine 2017 Kotlin 2018 KTX 2019 BenchMark 2020 Paging3 2022

    Navigation 2.4 Annotation 1.4 Collection 1.2 Fragment 1.4 Activity 1.4 Partially rewritten by Kotlin!
  6. // Navigation.java public final class Navigation { @NonNull public static

    View.OnClickListener createNavigateOnClickListener( @IdRes final int resId) { return createNavigateOnClickListener(resId, null); } @NonNull public static View.OnClickListener createNavigateOnClickListener( @IdRes final int resId, @Nullable final Bundle args) { return new View.OnClickListener() { @Override public void onClick(View view) { findNavController(view).navigate(resId, args); } }; } }
  7. // Navigation.kt public object Navigation { @JvmStatic @JvmOverloads public fun

    createNavigateOnClickListener( @IdRes resId: Int, args: Bundle? = null ): View.OnClickListener { return View.OnClickListener { view -> findNavController(view).navigate(resId, args) } } }
  8. TimeLine 2017 Kotlin 2018 KTX Android Jetpack 2019 BenchMark Kotlin

    first! Official Language 2020 Paging3 Window DataStore Compose https://developer.android.com/jetpack/androidx/versions/alpha-channel#august_11_2020 2022 Navigation 2.4 Annotation 1.4 Collection 1.2 Fragment 1.4 Activity 1.4 2023 (?) Room 2.5 Work 2.8 SavedState 1.2 …
  9. // WorkManager 2.7.1 val constraints = Constraints.Builder() .setRequiresCharging(true) .setRequiresBatteryNotLow(true) .setRequiresDeviceIdle(true)

    .build() // WorkManager 2.8.0-alpha02 val constraints = Constraints( requiresCharging = true, requiresBatteryNotLow = true, requiresDeviceIdle = true, ) Enhanced APIs for Kotlin users!
  10. Room Stable Auto Migrations Support for Kotlin 1.6 Room written

    in Kotlin starting from 2.5.0 Performance Improvements with KSP in 2.4.0 Room-Paging Support (Paging 3.0) Relational Query Methods androidx.room:room:2.4.2 https://developer.android.com/jetpack/androidx/releases/room#2.4.0
  11. // Auto Migrations @Database( version = 2, entities = [User::class],

    autoMigrations = [ AutoMigration ( from = 1, to = 2, spec = AppDatabase.MyAutoMigration::class ) ] ) abstract class AppDatabase : RoomDatabase() { @RenameTable(fromTableName = "User", toTableName = "AppUser") class MyAutoMigration : AutoMigrationSpec } https://developer.android.com/training/data-storage/room/migrating-db-versions#automated
  12. // Supports multimap return types // like Map, SparseArray, LongSparseArray,

    etc. // 1:1 Relation Map @Query("SELECT * FROM Song JOIN Artist ON Song.artistId = Artist.artistId") fun getSongAndArtist(): Map<Song, Artist> // 1:N Relation Map @Query("SELECT * FROM Artist JOIN Album ON Artist.id = Album.artistId") fun getArtistAndAlbums(): Map<Artist, List<Album>> https://developer.android.com/training/data-storage/room/accessing-data#multimap
  13. androidx.paging:paging:3.1.1 Paging Stable Load and display small chunks of data

    to improve network and system resources consumption.
  14. Paging Stable Stable support for Rx and Guava integrations Improvements

    to handling of invalid or stale data More comprehensive callbacks New introductory codelab for Paging 3 androidx.paging:paging:3.1.1 https://developer.android.com/jetpack/androidx/releases/paging#3.1.0
  15. Navigation Stable Integration between Navigation with Jetpack Compose Support for

    Multiple Back Stacks Support for two-pane layouts All artifacts rewritten in Kotlin androidx.navigation:navigation:2.4.2 https://developer.android.com/jetpack/androidx/releases/navigation#2.4.0
  16. class NavigationActivity : AppCompatActivity(R.layout.activity_navigation) <!-- res/layout/activity_navigation.xml --> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment"

    app:navGraph="@navigation/main_nav_graph" app:defaultNavHost="true" ... /> <!-- res/navigation/main_nav_graph.xml --> <navigation app:startDestination="@+id/two_pane"> <fragment android:id="@+id/two_pane" android:name="com.example.navigation.TwoPaneFragment" /> </navigation> https://github.com/CesarValiente/navigation-foldable
  17. https://github.com/CesarValiente/navigation-foldable class TwoPaneFragment : AbstractListDetailFragment() { override fun onCreateListPaneView( inflater:

    LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ListPaneBinding.inflate(inflater, container, false) } override fun onListPaneViewCreated(view: View, savedInstanceState: Bundle?) { oneFragmentButton.setOnClickListener { openDetails(R.id.one_fragment) } } ... } <!-- res/layout/list_pane.xml --> <Button android:id="@+id/one_fragment_button android:text="Fragment ONE" />
  18. class TwoPaneFragment : AbstractListDetailFragment() { ... private fun openDetails(destinationId: Int)

    { val detailNavController = detailPaneNavHostFragment.navController detailNavController.navigate( resId = destinationId, args = null, navOptions = navOptions { popUpTo(detailNavController.graph.startDestinationId) { inclusive = true } } ) slidingPaneLayout.open() } override fun onCreateDetailPaneNavHostFragment(): NavHostFragment { return NavHostFragment.create(R.navigation.detail_pane_nav_graph) } } https://github.com/CesarValiente/navigation-foldable
  19. <!-- res/navigation/detail_pane_nav_graph.xml --> <navigation app:startDestination="@+id/one_fragment"> <fragment android:id="@+id/one_fragment" android:name="com.example.navigation.OneFragment" /> <fragment

    android:id="@+id/two_fragment" android:name="com.example.navigation.TwoFragment" /> <fragment android:id="@+id/three_fragment" android:name="com.example.navigation.ThreeFragment" /> </navigation> class OneFragment : Fragment(R.layout.one_fragment) class TwoFragment : Fragment(R.layout.two_fragment) class ThreeFragment : Fragment(R.layout.three_fragment) https://github.com/CesarValiente/navigation-foldable
  20. DataStore Stable MAD Skills: DataStore goo.gle/mad-skills-datastore How to migrate from

    SharedPreferences to Proto DataStore. d.android.com/codelabs/android-proto-datastore#7 androidx.datastore:datastore:1.0.0 https://developer.android.com/jetpack/androidx/releases/datastore#1.0.0
  21. Lifecycle Stable Deprecated @OnLifecycleEvent Integration between ViewModel and Jetpack Compose

    Restartable Lifecycle-aware coroutines androidx.lifecycle:lifecycle:2.4.1 https://developer.android.com/jetpack/androidx/releases/lifecycle RC androidx.lifecycle:lifecycle:2.5.0+ ViewModel CreationExtras
  22. // You can use DefaultLifecycleObserver or LifecycleEventObserver instead. - class

    MyObserver(...) : LifecycleObserver { + class MyObserver(...) : DefaultLifecycleObserver { - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() { ... } - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause() { ... } } https://developer.android.com/training/data-storage/room/accessing-data#multimap Stable
  23. // Lifecycle-aware flow collection viewLifecycleOwner.lifecycleScope.launch { exampleProvider.exampleFlow() .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED) .collect

    { // Process the value. } } viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { flow1.collect { /* Process the value. */ } } launch { flow2.collect { /* Process the value. */ } } } } https://developer.android.com/topic/libraries/architecture/coroutines#lifecycle-aware Stable
  24. // current class MyActivity : AppCompatActivity() { private val viewModel:

    MyViewModel by viewModels() ... } class MyViewModel( private val savedStateHandle: SavedStateHandle, ) : ViewModel() { fun loadData(id: String) { ... } } RC
  25. // current class MyActivity : AppCompatActivity() { private val viewModel:

    MyViewModel by viewModels() override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory { return super.getDefaultViewModelProviderFactory() // SavedStateViewModelFactory } } class MyViewModel( private val savedStateHandle: SavedStateHandle, ) : ViewModel() { fun loadData(id: String) { ... } } RC
  26. class MyActivity : AppCompatActivity() { private val viewModel: MyViewModel by

    viewModels() } class MyViewModel( private val savedStateHandle: SavedStateHandle, + private val id: String, ) : ViewModel() { - fun loadData(id: String) { - ... - } } https://developer.android.com/topic/libraries/architecture/coroutines#restart RC
  27. class MyActivity : AppCompatActivity() { + private val key =

    object : CreationExtras.Key<String> {} private val factory = object : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create( modelClass: Class<T>, + extras: CreationExtras, ): T { val savedStateHandle = extras.createSavedStateHandle() + val id = extras[key].orEmpty() return MainViewModel( savedStateHandle = savedStateHandle, + id = id, ) as T } } override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory = factory ... } https://pluu.github.io/blog/android/2022/03/12/creationextras/ RC
  28. MAD Skills : Architecture Stable Materials on the best practices

    for Modern Android Development (MAD) http://goo.gle/mad-skills-architecture
  29. JankStats Alpha Compatible down to API Level 16 Identifies performance

    issues using internal heuristics Provides UI context to attribute data to user states and actions Reports results on every frame via a listener androidx.metrics:metrics-performance:1.0.0-alpha01 https://developer.android.com/topic/performance/jankstats
  30. androidx.profilesinstaller:profileinstaller:1.1.0 Baseline Profiles Stable Create profiles for your app that

    prepopulate ahead of time compilation tracest to reduce startup times and reduce jank
  31. Baseline Profiles Stable Provide custom profile rules in apps and

    libraries Startup and jank performance improvements Profiles added to popular Jetpack libraries androidx.profileinstaller:profileinstaller:1.1.0 https://developer.android.com/jetpack/androidx/releases/navigation#2.4.0
  32. Macrobenchmark Stable Now supports down to API Level 23 Add

    custom trace-based timing measurement with TraceSectionMetric Allow detection of audio underruns with AudioUnderrunMetric Added BaselineProfileRule to generate profiles for critical workflows androidx.benchmark:benchmark-macro:1.1.0 https://developer.android.com/topic/performance/benchmarking/macrobenchmark-overview
  33. androidx.slidingpanelayout:slidingpanelayout:1.2.0 SlidingPaneLayout Stable supports showing two panes side by side

    on larger devices and foldables, while automatically adapting to show only one pane at a time on smaller devices
  34. SlidingPaneLayout Stable Support for two-pane UX For Large Screen androidx.slidingpanelayout

    :slidingpanelayout:1.2.0 https://d.android.com/jetpack/androidx/releases/slidingpanelayout#1.2.0
  35. <!-- two_pane.xml --> <androidx.slidingpanelayout.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/sliding_pane_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Left

    Pane --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/list_pane" android:layout_width="280dp" android:layout_height="match_parent" android:layout_gravity="start"/> <!-- Right Pane --> <androidx.fragment.app.FragmentContainerView android:id="@+id/detail_container" android:layout_width="300dp" android:layout_weight="1" android:layout_height="match_parent" android:background="#ff333333" android:name="com.example.SelectAnItemFragment" /> </androidx.slidingpanelayout.widget.SlidingPaneLayout> https://developer.android.com/guide/topics/ui/layout/twopane
  36. <!-- two_pane.xml --> <androidx.slidingpanelayout.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/sliding_pane_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Left

    Pane --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/list_pane" android:layout_width="280dp" android:layout_height="match_parent" android:layout_gravity="start"/> <!-- Right Pane --> <androidx.fragment.app.FragmentContainerView android:id="@+id/detail_container" android:layout_width="300dp" android:layout_weight="1" android:layout_height="match_parent" android:background="#ff333333" android:name="com.example.SelectAnItemFragment" /> </androidx.slidingpanelayout.widget.SlidingPaneLayout> https://developer.android.com/guide/topics/ui/layout/twopane
  37. // A method on the Fragment that owns the SlidingPaneLayout,

    // called by the adapter when an item is selected. fun openDetails(itemId: Int) { childFragmentManager.commit { setReorderingAllowed(true) replace<ItemFragment>(R.id.detail_container, bundleOf("itemId" to itemId)) // If we're already open and the detail pane is visible, // crossfade between the fragments. if (binding.slidingPaneLayout.isOpen) { setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) } } binding.slidingPaneLayout.open() } https://developer.android.com/guide/topics/ui/layout/twopane
  38. Supports foldable phones to adjust how content is displayed Smart

    layout avoids placing content in occluded areas Already integrated into SlidingPaneLayout WindowManager Stable androidx.window:window:1.0.0 https://developer.android.com/jetpack/androidx/releases/window#1.0.0
  39. class PreferenceActivity : AppCompatActivity(R.layout.activity_preference) <!-- res/layout/activity_preference.xml --> <androidx.fragment.app.FragmentContainerView android:name="com.example.preferences.TwoPanePreference" ...

    /> class TwoPanePreference : PreferenceHeaderFragmentCompat() { override fun onCreatePreferenceHeader(): PreferenceFragmentCompat { return HeaderPreference() } } class HeaderPreference : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.preferences, rootKey) } } https://github.com/CesarValiente/preferences-foldable
  40. <!-- res/xml/preference.xml --> <PreferenceScreen> <Preference android:fragment="com.example.preferences.OneFragment" android:key="pref_one" ... /> <Preference

    android:fragment="com.example.preferences.TwoFragment" android:key="pref_two" ... /> <Preference android:fragment="com.example.preferences.ThreeFragment" android:key="pref_three" ... /> </PreferenceScreen> https://github.com/CesarValiente/preferences-foldable
  41. // Use the DragStartHelper class to easily support initiating drag

    and drop in response to // both long press and mouse drag events. Note the call to attach() at the end. Without it, // the listener would never actually be attached to the view. Also note that attach() replaces // any OnTouchListener or OnLongClickListener already attached to the view. DragStartHelper(binding.textDragItem) { view, _ -> val text = (view as TextView).text // Create the ClipData to be shared val dragClipData = ClipData.newPlainText(/*label*/"Text", text) // Use the default drag shadow val dragShadowBuilder = View.DragShadowBuilder(view) // Initiate the drag. Note the DRAG_FLAG_GLOBAL, which allows for drag events to be istened // to by apps other than the source app. view.startDragAndDrop(dragClipData, dragShadowBuilder, null, DRAG_FLAG_GLOBAL) }.attach() https://github.com/android/user-interface-samples/tree/main/DragAndDrop
  42. DropHelper.configureView( /* activity */ this, binding.textDropTarget, /* mimeTypes */ arrayOf(

    ClipDescription.MIMETYPE_TEXT_PLAIN, "application/x-arc-uri-list" // Support external items on Chrome OS Android 9 ), DropHelper.Options.Builder() .setHighlightColor(getColor(R.color.purple_300)) .build() ) { view, payload -> resetDropTarget() val item = payload.clip.getItemAt(0) val (_, remaining) = payload.partition { it == item } if (payload.clip.description.hasMimeType(MIMETYPE_TEXT_PLAIN) { binding.textDropTarget.text = item.text } // Allow the system to handle any remaining ClipData.Item objects if applicable // remaining } https://github.com/android/user-interface-samples/tree/main/DragAndDrop
  43. AppCompat Stable Emoji2 integration allows default support for the latest

    emojis Custom locale selection backported from Tiramisu (Android 13) Uses Play splits to download additional locales androidx.appcompat:appcompat:1.4.2 https://developer.android.com/guide/topics/ui/look-and-feel/emoji2 androidx.appcompat:appcompat:1.6.0+
  44. // Get app locales val locales: LocaleListCompat = AppCompatDelegate.getApplicationLocales() //

    Set app locales val locales: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY") // or LocaleListCompat.create(Locale.KOREA) AppCompatDelegate.setApplicationLocales(locales) https://developer.android.com/about/versions/13/features/app-languages#androidx-impl
  45. override fun attachBaseContext(newBase: Context) { if (SDK_INT < 33) {

    // Preferred locales are managed automatically on API level 33+, // but we need to load them manually on earlier platform versions. val locales = loadLocalesFromPreferences() AppCompatDelegate.setApplicationLocales(locales) } super.attachBaseContext(newBase) } <service android:name="androidx.appcompat.app.AppLocalesMetadataHolderService" android:enabled="false" android:exported="false"> <meta-data android:name="autoStoreLocales" android:value="true" /> </service> https://developer.android.com/about/versions/13/features/app-languages#androidx-impl
  46. override fun attachBaseContext(newBase: Context) { if (SDK_INT < 33) {

    // Preferred locales are managed automatically on API level 33+, // but we need to load them manually on earlier platform versions. val locales = loadLocalesFromPreferences() AppCompatDelegate.setApplicationLocales(locales) } super.attachBaseContext(newBase) } <service android:name="androidx.appcompat.app.AppLocalesMetadataHolderService" android:enabled="false" android:exported="false"> <meta-data android:name="autoStoreLocales" android:value="true" /> </service> https://developer.android.com/about/versions/13/features/app-languages#androidx-impl
  47. <androidx.constraintlayout.widget.ConstraintLayout> <Button android:id="@+id/clear" android:text="C" /> ... <TextView android:id="@+id/calculatorText" android:background="@color/cardview_shadow_start_color" android:text="100"

    android:gravity="bottom|right" /> <Button android:id="@+id/btn0" android:text="0" /> ... </androidx.constraintlayout.widget.ConstraintLayout> https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  48. <androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.helper.widget.Grid android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="match_parent" app:constraint_referenced_ids=" calculatorText,btn0, clear,neg,percent,div,btn7,btn8,btn9,mult,btn4, btn5,btn6,sub,btn1,btn2,btn3,plus,btn0,dot,equal" app:grid_columns="4"

    app:grid_rows="7" app:grid_horizontalGaps="5dp" app:grid_verticalGaps="5dp" app:grid_orientation="horizontal" app:grid_spans="0:2x4,24:1x2" /> </androidx.constraintlayout.widget.ConstraintLayout> https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  49. <androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.helper.widget.Grid android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="match_parent" app:constraint_referenced_ids=" calculatorText,btn0, clear,neg,percent,div,btn7,btn8,btn9,mult,btn4, btn5,btn6,sub,btn1,btn2,btn3,plus,btn0,dot,equal" app:grid_columns="4"

    app:grid_rows="7" app:grid_horizontalGaps="5dp" app:grid_verticalGaps="5dp" app:grid_orientation="horizontal" app:grid_spans="0:2x4,24:1x2" /> </androidx.constraintlayout.widget.ConstraintLayout> https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  50. <androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.helper.widget.Grid android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="match_parent" app:constraint_referenced_ids=" calculatorText,btn0, clear,neg,percent,div,btn7,btn8,btn9,mult,btn4, btn5,btn6,sub,btn1,btn2,btn3,plus,btn0,dot,equal" app:grid_columns="4"

    app:grid_rows="7" app:grid_horizontalGaps="5dp" app:grid_verticalGaps="5dp" app:grid_orientation="horizontal" app:grid_spans="0:2x4,24:1x2" /> </androidx.constraintlayout.widget.ConstraintLayout> https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  51. <androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.helper.widget.Grid android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="match_parent" app:constraint_referenced_ids=" calculatorText,btn0, clear,neg,percent,div,btn7,btn8,btn9,mult,btn4, btn5,btn6,sub,btn1,btn2,btn3,plus,btn0,dot,equal" app:grid_columns="4"

    app:grid_rows="7" app:grid_horizontalGaps="5dp" app:grid_verticalGaps="5dp" app:grid_orientation="horizontal" app:grid_spans="0:2x4,24:1x2" /> </androidx.constraintlayout.widget.ConstraintLayout> https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  52. “All new Play Store features are built on top of

    this framework. Compose has been instrumental in unlocking better velocity and smoother landings for the app.” 01 “Compose makes it much easier to define our own components and to make their API contracts more explicit, flexible, and intuitive.” 02 “Jetpack Compose is a critical part of our technical strategy. The productivity gains are massive.” 03 Jetpack Compose Google Play Twitter AirBnB
  53. val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms",

    certificates = R.array.com_google_android_gms_fonts_certs ) val MontserratFont = GoogleFont(name = "Montserrat") val MontserratFontFamily = FontFamily( Font(googleFont = MontserratFont, fontProvider = provider) ) Text( fontFamily = MontserratFontFamily, text = "Hello World!" ) https://github.com/android/compose-samples/pull/787
  54. <androidx.coordinatorlayout.widget.CoordinatorLayout> <com.google.android.material.appbar.AppBarLayout> <com.google.android.material.appbar.CollapsingToolbarLayout> <androidx.appcompat.widget.AppCompatImageView /> <androidx.appcompat.widget.Toolbar /> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.compose.ui.platform.ComposeView

    android:id="@+id/compose_view" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <com.google.android.material.floatingactionbutton.FloatingActionButton /> </androidx.coordinatorlayout.widget.CoordinatorLayout> Nested Scrolling Interop Phase 1: Scrolling compose in cooperating view (I5d1ac)
  55. @ExperimentalComposeUiApi class ComposeInAndroidCoordinatorLayout : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.compose_in_android_coordinator_layout) findViewById<ComposeView>(R.id.compose_view).apply { setContent { val nestedScrollInterop = rememberNestedScrollInteropConnection(this) LazyColumn(modifier = Modifier.nestedScroll(nestedScrollInterop)) { items(20) { item -> Box(...) { Text(item.toString()) } } } } } } } Nested Scrolling Interop Phase 1: Scrolling compose in cooperating view (I5d1ac)
  56. <!-- res/layout/android_in_compose_nested_scroll_interop.xml —> <FrameLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/main_list" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>

    <!-- res/layout/android_in_compose_nested_scroll_interop_list_item.xml —> <FrameLayout> <TextView android:id="@+id/list_item" /> </FrameLayout> Nested Scrolling Interop Phase 2: A scrolling view child inside a compose parent (If7949)
  57. val ToolbarHeight = 48.dp @Composable private fun NestedScrollInteropComposeParentWithAndroidChild() { val

    toolbarHeightPx = with(LocalDensity.current) { ToolbarHeight.roundToPx().toFloat() } val toolbarOffsetHeightPx = remember { mutableStateOf(0f) } val nestedScrollConnection = remember { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val delta = available.y val newOffset = toolbarOffsetHeightPx.value + delta toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f) return Offset.Zero } } } ... } Nested Scrolling Interop Phase 2: A scrolling view child inside a compose parent (If7949)
  58. @Composable private fun NestedScrollInteropComposeParentWithAndroidChild() { ... Box( Modifier .fillMaxSize() .nestedScroll(nestedScrollConnection)

    ) { TopAppBar( modifier = Modifier .height(ToolbarHeight) .offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) }, title = { Text("toolbar offset is ${toolbarOffsetHeightPx.value}") } ) ... } ) } Nested Scrolling Interop Phase 2: A scrolling view child inside a compose parent (If7949)
  59. @Composable private fun NestedScrollInteropComposeParentWithAndroidChild() { ... AndroidView( { context ->

    LayoutInflater.from(context) .inflate(R.layout.android_in_compose_nested_scroll_interop, null).apply { with(findViewById<RecyclerView>(R.id.main_list)) { layoutManager = LinearLayoutManager(context, VERTICAL, false) adapter = NestedScrollInteropAdapter() } }.also { ViewCompat.setNestedScrollingEnabled(it, true) } }, modifier = Modifier.padding(top = ToolbarHeight).fillMaxWidth(), ) } Nested Scrolling Interop Phase 2: A scrolling view child inside a compose parent (If7949)
  60. // Compose 1.1 + RecyclerView 1.2 import androidx.compose.ui.platform.ComposeView class MyComposeAdapter

    : RecyclerView.Adapter<MyComposeViewHolder>() { override fun onCreateViewHolder(...): MyComposeViewHolder { return MyComposeViewHolder(ComposeView(parent.context)) } override fun onViewRecycled(holder: MyComposeViewHolder) { + holder.composeView.disposeComposition() } } class MyComposeViewHolder(val composeView: ComposeView) : RecyclerView.ViewHolder(composeView) { init { + composeView.setViewCompositionStrategy( + ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed + ) } } https://d.android.com/jetpack/compose/interop/compose-in-existing-ui#compose-recyclerview
  61. // Compose 1.2 + RecyclerView 1.3 import androidx.compose.ui.platform.ComposeView class MyComposeAdapter

    : RecyclerView.Adapter<MyComposeViewHolder>() { override fun onCreateViewHolder(...): MyComposeViewHolder { return MyComposeViewHolder(ComposeView(parent.context)) } // override fun onViewRecycled(holder: MyComposeViewHolder) { // holder.composeView.disposeComposition() // } } class MyComposeViewHolder(val composeView: ComposeView) : RecyclerView.ViewHolder(composeView) { // init { // composeView.setViewCompositionStrategy( // ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed // ) // } } https://d.android.com/jetpack/compose/interop/compose-in-existing-ui#compose-recyclerview
  62. @OptIn(ExperimentalFoundationApi::class) LazyVerticalGrid( columns = GridCells.Fixed(2), verticalArrangement = Arragement.spaceBy(16.dp), horizontalArrangement =

    Arragement.spaceBy(16.dp), ) { items(data) { item -> Item(item) } } https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  63. // New! LazyHorizontalGrid( rows = GridCells.Fixed(2), verticalArrangement = Arragement.spaceBy(16.dp), horizontalArrangement

    = Arragement.spaceBy(16.dp), ) { items(data) { item -> Item(item) } } https://speakerdeck.com/fornewid/whats-new-in-jetpack-2022
  64. Thank you! Android Developer / GDSC HUFS HUFS I.C.E @jdoongxx

    @JaesungLeee https://speakerdeck.com/jaesungleee/whats-new-in-jetpack-2022 [email protected] https://d.android.com/jetpack https://www.youtube.com/watch?v =jTd82lcuHTU&t=242s Resources Jaesung Lee