Lzyprime blog (Github) was created on November 24, 2020.qq and email: 2383518170

Kotlin & Android notes


Lambda. :

Navigation is an important component of Android Jetpack, which was introduced about 3 years ago at Google I/O 2018. Mainly used for organizing fragments, through fragments to achieve the display of different content fragments. Including the switch between the same level, jump between different levels (such as the list item jump details page), instead of the previous jump Activity mode, launch a single Activity mode.

Navigation official Site

withActivityComparative benefits:

  1. Get the same copyActivity ViewModel.ViewModelActivityIs unit share, sameActivityUnder theFragmentYou can get the same copyViewModelSo if you jump directlyActivityData sharing should be handled by itself, either by passing it or fetching it from the global cache, and also by considering replica consistency, which means that if I make changes to the data on one page, all other pages that use the data should be synchronized.

When the Provider plug-in is used to implement state management, the jump to another Route cannot be obtained through The Provider. Of (context) unless the Provider is wrapped in the outer layer of the MaterialApp. Data processing is similar to Android activities. Packages work well in the outermost layer because the MaterialApp generation constructs a Navigator to organize all pages. Save the information with List<_RouteEntry> _history and GlobalKey

_overlayKey. So all pages are children of The MaterialApp.

Navigator2.0, which was recently released with flutter 1.22, allows you to organize pages using List > pages, which is similar to the Android navigation component, flutter Page is like the Android Fragment

  1. Navigation diagrams can be done by dragging boxes with visual tools. Each page is called a “destination”, through the line between, set parameters to achieve the page jump constraints, while you can set the transition animation. All navigation resources are stored in the Navigation folder under the resources folder. Kotlin DSL code is also supported to complete navigation Settings.

  2. Safe Args passes data. Safe Arges website address. Ensure safe transfer of data.

In general, it is highly recommended that you only pass the minimum amount of data between destinations. For example, you should pass the key to retrieve the object rather than the object itself, because the total space to hold all the state on Android is limited. “The same applies to flutter. There is no good replica consistency scheme in Flutter, so I cached the beans when the data is parsed. The same data is constructed only once, and then it is all fetched or updated from the cache. The factory constructor is used to cache, generate, update, obtain and other operations of the data invisible, to achieve a simple Loc effect. (TODO: more later)

Note:

  1. System return button and event handling. jumpFragmentTo intercept and setActivityThe return button event, otherwise the wholeActivityIt’s closed. At the same time, the status updates of other components need to be maintained by themselves. Refer to:Use NavigationUI to update the interface components

This problem also exists in flutter Navigator2.0.

  1. At the same levelFragmentSwitching requires a rebuild and does not record state. By putting the currentFragmentManagertonavigationTo achieve a page switch, each switch to rebuildFragment.

Demo: Add login page and details page

Continue development from the previous demo.

# android navigation demo
# warehouse address: https://github.com/lzyprime/android_demos
# branch: navigation

git clone -b navigation https://github.com/lzyprime/android_demos
Copy the code

1. The import

Use the portal address

If Safe Args is used, the plug-in should be introduced at the top level, or the Bundle should be implemented instead of Safe Args

// project gradle
buildscript {
    repositories {
        google()
    }
    // Safe Args
    dependencies{...def nav_version = 2.3.1 ""
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"}}Copy the code
// module gradle
plugin {
    ...

    id "androidx.navigation.safeargs.kotlin"
}

dependencies{...// navigation
    def nav_version = 2.3.1 ""
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    // Feature module Support
    //implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
    // Testing Navigation
    //androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
    // Jetpack Compose Integration
    / / implementation "androidx. Navigation: navigation - compose: 1.0.0 - alpha01"
}
Copy the code

2. Navigation chart and destination

Refer to design navigation chart and condition navigation (official website address).

Add a new Android resource, type Navigation, and create a Navigation directory.

Click Add New Destination (Fragment). If it already exists, it will be displayed in the list. Be sure to use Fragment units

Add 3 destinations. The LoginFragment is replaced by the PhotoListFragment after a successful login, so set the popUpTo parameter. Reference navigation to the destination

Each navigation rule has its own ID. Use for NavController. Navigate to implement a jump.

The LoginFragment is the start destination, and the Home page icon is displayed before the name.

2. ToActivityaddNavHost

Add a NavHostFragment to the Layout file and you will receive a warning ⚠ asking you to use the FragmentContainerView as the Fragment container. Click Fix to apply the suggestion.

3. Login function andActivityDestination switching

Now that the app is ready to launch, it’s going to show you the origin destination which is the LoginFragment.

Demo uses api.unsplash.com/, which actually only requires access_key, so the login page only requires an input box and a login button. The list is requested when you click login and is replaced with a PhotoListFragment page if successful.


// LoginFragment

class LoginFragment : Fragment(R.layout.fragment_login) {
    private val viewModel: ListPhotoViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
        super.onViewCreated(view, savedInstanceState)
        login_btn.setOnClickListener {
            val text = access_key_eidt_text.text.toString()
            if (text.isEmpty()) {
                Toast.makeText(context, "Can't be empty!", Toast.LENGTH_SHORT).show()
            } else {
                Net.ACCESS_KEY = text
                viewModel.refreshListPhotos()
            }
        }
    }
}
Copy the code

Reference navigation to the destination, using NavHost’s NavController to implement the destination jump.

See Using NavigationUI to update the interface component and set the top appBar and system return events accordingly

// MainActivity


@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: ListPhotoViewModel by viewModels()
    private var loginSuccess = false
    private lateinit var appBarConfiguration: AppBarConfiguration
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHost = supportFragmentManager.findFragmentById(R.id.mainNavHost) as NavHostFragment
        val navController = navHost.findNavController()

        appBarConfiguration = AppBarConfiguration(setOf(R.id.loginFragment, R.id.photoListFragment))
        / / the top appBar
        setupActionBarWithNavController(navController, appBarConfiguration)

        viewModel.listPhotos.observe(this) {
            // The list is not empty, the login succeeded
            if(! loginSuccess && it.isNotEmpty()) { loginSuccess =true
                Toast.makeText(this."Login successful", Toast.LENGTH_SHORT).show()
                navController.navigate(R.id.action_loginFragment_to_photoListFragment)
            }
        }
    }

    override fun onSupportNavigateUp(a): Boolean {
        // Whether to display the back button
        return mainNavHost.findNavController().navigateUp(appBarConfiguration)
                || super.onSupportNavigateUp()
    }

    override fun onBackPressed(a) {
        // The system returns an event
        if(! mainNavHost.findNavController().popBackStack()) finish() } }Copy the code

4. Click the picture to enter the details pageSafe ArgsPass image link

Refer to passing data between destinations and visually edit the parameters to be passed on the navigation diagram edit page.

SpecifyAmountFragmentDirections ConfirmationFragmentArgs for plug-in generated automatically, can be found in Java (generated) directory

//PhotoListFragment Jump logic

class PhotoListFragment : Fragment(R.layout.fragment_photo_list) {
...


                override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                    val photo = photos[position]

                    with(holder.itemView as ImageView) {
                        Glide.with(this).load(photo.urls.raw).into(this)
                        setOnClickListener {
                            val directions = PhotoListFragmentDirections.actionPhotoListFragmentToDetailFragment(photo.urls.raw)
                            this@PhotoListFragment.findNavController().navigate(directions)
                        }
                    }
                }

...
}
Copy the code

If you use the -ktx version, you can use by navArgs() to get the passed argument

// DetailFragment

class DetailFragment : Fragment(R.layout.fragment_detail) {
    private val args by navArgs<DetailFragmentArgs>()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
        super.onViewCreated(view, savedInstanceState)
        Glide.with(imageView).load(args.imageSrc).into(imageView)
    }
}
Copy the code