ºÝºÝߣ

ºÝºÝߣShare a Scribd company logo
A Single Activity App with
Jetpack¡¯s Navigation Component
By Boonya Kitpitak
There is a problem in Activity
transition?
It flickers
Source: https://mikescamell.com/shared-element-transitions-part-5/
A Single activity app with Jetpack's Navigation Component
How to share data between
Activities?
Application Scope
Activity 1
Fragment
Activity 2
Fragment
Activity 3
Fragment
Service Content Provider
Singleton
Data holder
Application Scope
Activity
Fragment Fragment Fragment
SharedViewModelSharedViewModel
Service Content Provider
It¡¯s time to try Single Activity¡­
How?
A Single activity app with Jetpack's Navigation Component
Outline ? 3 Essential Navigation Component
Concepts
? Features of Android Jetpack¡¯s Navigation
Component
? Additional Note
? Conclusion
? Q/A
Pokemon Info App
Data from: https://pokeapi.co
3 Essential Concepts of Navigation
Component
1. Navigation Graph
A navigation graph is a new type resource file that contains all
of your destinations and actions. The graph represents all of
your app's navigation paths.
Location
A Single activity app with Jetpack's Navigation Component
Destination
Action
A Single activity app with Jetpack's Navigation Component
Animation
Argument
Pop Behavior
Launch Options
XML Version
2. NavHostFragment
An empty container where destinations are swapped in
and out as a user navigates through your app.
<androidx.drawerlayout.widget.DrawerLayout ¡­>
<androidx.appcompat.widget.LinearLayoutCompat ¡­>
<androidx.appcompat.widget.Toolbar ¡­/>
<fragment
android:id="@+id/mainHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.navigation.NavigationView ¡­/>
</androidx.drawerlayout.widget.DrawerLayout>
<fragment
android:id="@+id/mainHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.navigation.NavigationView ¡­/>
</androidx.drawerlayout.widget.DrawerLayout>
3. NavController
An object that manages app navigation within a NavHost.
Each NavHost has its own corresponding NavController.
NavController can be retrieved by Fragment, Activity, or View
Instantiate NavController
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)
Navigate with ID
navController.navigate(R.id.berryDetailFragment)
Navigate Direction
val direction = BerryListFragmentDirections
.actionBerryListFragmentToBerryDetailFragment()
navController.navigate(direction)
Navigation Component Features
1. Passing data with Safe Args Gradle Plugin
Plugin that generates simple object and builder classes for type-
safe access to arguments specified for destinations and actions.
fun newInstance(
obj: Object1? = null,
id: Int,
minimumPrice: Int? = null,
promotionId: Int? = null,
selectionId: Int? = null,
itemPosition: Int? = null
): SomeFragment {
val fragment = PizzaOptionFragment()
fragment.arguments = Bundle().apply {
putParcelable(Constants.Intent.Obj1, obj)
putInt(Constants.Intent.ID, id)
minimumPromotionPrice?.let { putInt(Constants.Intent.Promotion.MINIMUM_PRICE, it)}
promotionId?.let { putInt(Constants.Intent.Promotion.PROMOTION_ID, it) }
selectionId?.let { putInt(Constants.Intent.Promotion.SELECTION_ID, it) }
itemPosition?.let { putInt(Constants.Intent.Promotion.ITEM_POSITION, it) }
}
return fragment
}
BerryFragment to BerryDetailFragment
url
Argument can be either optional or mandatory
Passing Data
val direction = BerryListFragmentDirections
.actionBerryListFragmentToBerryDetailFragment(item.url)
navController.navigate(direction)
Getting Data
val args: BerryDetailFragmentArgs = arguments?.let{
BerryDetailFragmentArgs.fromBundle(it)
}
val berryUrl: String = args.url
Getting Data
BerryDetailFragmentArgs.fromBundle(it)
Getting Data
val berryUrl: String = args.url
? 2. Navigation UI Libs
Help managing navigation with the top app bar, the
navigation drawer, and bottom navigation.
Gradle Dependency
//navigation
implementation "androidx.navigation:navigation-runtime-ktx:2.1.0-alpha05"
implementation ¡®androidx.navigation:navigation-fragment-ktx:2.1.0-alpha05'
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0-alpha05'
XML LAYOUT
<layout>
<androidx.drawerlayout.widget.DrawerLayout¡­>
<androidx.appcompat.widget.LinearLayoutCompat
¡­>
<androidx.appcompat.widget.Toolbar
¡­/>
<fragment
android:id="@+id/mainHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.navigation.NavigationView
¡­
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
<fragment
android:id="@+id/mainHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
<com.google.android.material.navigation.NavigationView
¡­
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
Menu
<menu ¡­>
<item
android:id="@+id/pokemonListFragment"
android:icon="@drawable/ic_pikachu"
android:title="@string/label_pokemon"
app:showAsAction="never" />
<item
android:id="@+id/berryListFragment"
android:icon="@drawable/ic_razz_berry"
android:title="@string/label_berries"
app:showAsAction="never" />
</menu>
android:id="@+id/pokemonListFragment"
android:id="@+id/berryListFragment"
Navigation Graph
<navigation ¡­app:startDestination=¡°@id/pokemonListFragment¡±>
<fragment android:id=¡°@+id/berryListFragment" ¡­/>
<fragment android:id=¡°@+id/pokemonListFragment¡± ¡­/>
<dialog android:id=¡°@+id/pokemonDetailBottomSheet¡± ¡­/>
<fragment android:id=¡°@+id/berryDetailFragment¡± ¡­/>
</navigation>
<fragment android:id=¡°@+id/berryListFragment" ¡­/>
<fragment android:id=¡°@+id/pokemonListFragment¡± ¡­/>
Activity
class MainActivity : AppCompatActivity() {
private val navController: NavController
by lazy { Navigation.findNavController(this, R.id.mainHostFragment) }
¡­
override fun onCreate(savedInstanceState: Bundle?) {
¡­
with(binding) {
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.pokemonListFragment,
R.id.berryListFragment,
R.id.pokemonDetailBottomSheet
),
drawerLayout
)
toolbar.setupWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
}
private val navController: NavController
by lazy { Navigation.findNavController(this, R.id.mainHostFragment) }
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.pokemonListFragment,
R.id.berryListFragment,
R.id.pokemonDetailBottomSheet
),
drawerLayout
)
toolbar.setupWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
A Single activity app with Jetpack's Navigation Component
3. Deeplink
The Navigation component lets you create two different
types of deep links: explicit and implicit.
Explicit Deeplink: Navigating within the app by PendingIntent
NavDeepLinkBuilder(context).setGraph(R.navigation.main_navigation)
.setDestination(R.id.berryDetailFragment)
.setArguments(url)
.createPendingIntent()
.send()
Implicit Deep link: Navigating from outside of the app
2 Steps
? Declare Deeplink in Navigation Graph
? Declare NavGraph in Manifest
1. Navigation Graph
1. Navigation Graph
<navigation ¡­>
<fragment android:id="@+id/berryListFragment"
¡­>
<action android:id="@+id/action_berryListFragment_to_berryDetailFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:destination=¡°@id/berryDetailFragment"/>
<deepLink app:uri="www.pokemoninfo.com/berrylist" />
</fragment>
</navigation>
1. Navigation Graph
<deepLink app:uri="www.pokemoninfo.com/berrylist" />
</fragment>
</navigation>
2. Manifest
<manifest ¡­>
<uses-permission android:name="android.permission.INTERNET"/>
<application ¡­>
<activity ¡­>
<nav-graph android:value=¡°@navigation/main_navigation"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
2. Manifest
<nav-graph android:value=¡°@navigation/main_navigation"/>
Additional Note
? Where is startActivityForResult?
? How to handle a complex navigation flow?
? Are there any problems?
A Single activity app with Jetpack's Navigation Component
Conclusion
Ben (Boonya Kitpitak)
Android Developer at Oozou
Medium: https://medium.com/@boonya.kitpitak
Github: https://github.com/BenBoonya
Pokemon Info Repository
https://github.com/BenBoonya/android-pokemon-info
Facebook Page
https://www.facebook.com/codewithoutbrain/
Promocode For Java to Kotlin for Android Dev at Skooldio
https://v1.skooldio.com/courses/kotlin-for-android-2
Discount Code:
ANDROIDCONF
Q/A

More Related Content

A Single activity app with Jetpack's Navigation Component

Editor's Notes

  1. How many of you experience ¡­ I¡¯ve playing around with Jetpack¡­ it would say it makes a lot of thing easier. This architecture only have one activity .. Start problem statement
  2. In this video, it uses shared element transition to animate between activity.
  3. The way to fix this is not intuitive. From what I¡¯ve heard there won¡¯t be a release to fix this problem. we might need to add these line of code forever. But this problem won¡¯t occur in the transition between Fragments.
  4. We can treat activity as bigger component
  5. By the reason I¡¯ve told you some of you might wanna try Single Activity but how?
  6. By using JetPack Navigation component, we can implement single activity app really easy.
  7. First of all I would like to show you the little application that I build as a demo for this talk.
  8. There¡¯ll be a link to the source code of this project in my Github repo at the end of this talk. As the talk goes you¡¯ll see how I built this app by navigation component.
  9. This is a new type resource previously we have drawable, menu now we have navigation graph. Navigation graph represent the screens and navigation path in your app.
  10. navigation graph file is in the resource directory under navigation folder. When you open it the file you¡¯ll navigation editor like this.
  11. Navigation graph come with Nav editor. You can either choose to edit in design view or raw xml file.Let¡¯s take a closer look.
  12. We call each screen a destination. The destination can be Fragment, Dialog, or BottomSheetDialogFragment. And each destination can be connected by action represented as arrow in the graph.
  13. Here are the things that we can do with the editor. First thing is action animation.
  14. we can add argument to each destination. It can be parcelable or primitive things like Int or string.
  15. specify pop to destination.
  16. Like SingleTop Flag when start an activity.
  17. Build the app when finishing creating your graph. There¡¯ll be some auto generated class created to comfort our development.
  18. After we have our graph set up. How could we display this graph in our activity
  19. This is the layout file of main_activity.xml
  20. The app:defaultNavHost="true" attribute ensures that your NavHostFragment intercepts the system Back button. navGraph is where you put the graph that you have defined in the previous step in.
  21. Here come the third essential element we have destination and action defined then we have a container for them to display now what left is the thing to manage all of them. That thing called NavController
  22. In activity you have to specify id of NavHost. In case there¡¯re multiple NavHost in an activity.
  23. We can navigate to destination by ID like this.
  24. Or we can use direction it¡¯s auto-generated class which create base on the navigation graph. But why can¡¯t we just navigate with ID. The reason is we need to use direction for passing data between destination. I will talk about this in the next topic.
  25. This plugin will auto generate some classes to make passing data between destination safer and easier. Previously, we need to pass the data to fragment by newInstance method right?
  26. Some are optional some are not you have to check in again before putting in argument. SafeArg can safe from this mess.
  27. Click on destination to add argument. It can be optional or mandatory.
  28. if there¡¯s more param it can be pass via function. In this case I define url as mandatory param so the function actionBerryListFragment¡­ won¡¯t be able to compile if I don¡¯t pass item url in.
  29. The data can be retrieved via BerryDetailFragmentArgs
  30. Basically use can deal with every argument the BerryDetailFragmentArg
  31. If you have worked with navigation drawer or bottom navigation, you may notice that there¡¯re some overhead. Navigation UI libs help get rid of it.
  32. You need to add one more dependency
  33. I¡¯ll show you the step to set up navigation drawer with navigation ui Lib.
  34. create navHostFragment like what we did before.
  35. In addition, you need to add NavigationView with menu specified.
  36. It¡¯s the typical menu resource but the id need to be exactly the same as fragment id in navigation graph.
  37. As you can see that it has exactly the same name as in menu resource.
  38. We have everything set up now we need to bind them all together.
  39. Navigation controller going to bind them all together.
  40. create appBarConfiguration to control the behavior of hamburger icon and back button.
  41. set up toolbar with NavController for showing correct toolbar label
  42. Navigation component libs also provide the way to handle deep link
  43. can navigate from destination in one graph to destination in another graph. We didn¡¯t use it in our example
  44. In our example we use implicit deeplink to navigate from outside of the app like browser or other apps.
  45. Jetpack navigation component make my life a lot easier. I can visualize the navigation in the app and compare side by side with the flow from the designer. as well as passing the data safely between screen. I understand that this architecture is not for everyone. Just like any other new architecture if the old architecture work well for you. You don¡¯t need to change it. But if you want to start new project it might worth a try.