Android在kts中使用navigation及Args

Android在kts中使用navigation及Args

前言:

​ 之前在项目中使用过navigation,但都是以Groory的方式,最近一年多使用kts后忍不住把项目都改成kts的方式,不过其中也遇到不少坑,今天就讲解一下如何在kts中使用navigation和安全地传递参数Args。

1.项目依赖导入:

在libs.versions.toml文件下添加以下依赖:

复制代码
navigationFragmentKtx = "2.6.0"
navigationUiKtx = "2.6.0"

navigation-fragment = {group = "androidx.navigation",name = "navigation-fragment-ktx",version.ref = "navigationFragmentKtx"}
navigation-ui = {group = "androidx.navigation",name = "navigation-ui-ktx",version.ref = "navigationUiKtx"}

navigation-safe-args = { id = "androidx.navigation.safeargs.kotlin", version = "2.8.0" }

2.app目录的build.gradle配置:

kotlin 复制代码
plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
    alias(libs.plugins.navigation.safe.args)
}

    implementation(libs.navigation.fragment)
    implementation(libs.navigation.ui)

3.项目的build.gradle配置:

kotlin 复制代码
plugins {
    alias(libs.plugins.androidApplication) apply false
    alias(libs.plugins.jetbrainsKotlinAndroid) apply false
    alias(libs.plugins.navigation.safe.args) apply false
}

4.在布局添加导航组件:

在res目录添加navigation------nav_graph文件

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/mainFragment">

    <fragment
        android:id="@+id/mainFragment"
        android:label="fragment_main"
        android:name="com.cloud.flowbusdemo.fragment.MainFragment"
        tools:layout="@layout/fragment_main">

        <action
            android:id="@+id/action_mainFragment_to_secondFragment"
            app:destination="@id/secondFragment"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"/>
        <action
            android:id="@+id/action_mainFragment_to_mineFragment"
            app:destination="@id/mineFragment"
            app:enterAnim="@anim/slide_in_left"
            app:exitAnim="@anim/slide_in_right"
            app:popEnterAnim="@anim/slide_out_left"
            app:popExitAnim="@anim/slide_out_right" />
        <argument
            android:name="name"
            app:argType="string"
            android:defaultValue="xiaozhang"/>
        <argument
            android:name="age"
            app:argType="integer"
            android:defaultValue="1"/>
    </fragment>

    <fragment
        android:id="@+id/secondFragment"
        android:label="fragment_second"
        android:name="com.cloud.flowbusdemo.fragment.SecondFragment"
        tools:layout="@layout/fragment_second"/>

    <fragment
        android:id="@+id/mineFragment"
        android:name="com.cloud.flowbusdemo.fragment.MineFragment"
        android:label="fragment_mine"
        tools:layout="@layout/fragment_mine" />
</navigation>

5.Fragment_main布局:

fragment_mine.xml

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvTitle"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textSize="18sp"
        android:textColor="@color/white"
        android:gravity="center"
        android:text="MainFragment"
        android:layout_margin="20dp"
        android:background="@color/design_default_color_primary"
        tools:ignore="MissingConstraints" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/btnToSecondFragment"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toBottomOf="@id/tvTitle"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textAllCaps="false"
        android:textColor="@color/white"
        android:gravity="center"
        android:layout_margin="20dp"
        android:background="@color/design_default_color_primary"
        android:text="打开SecondFragment"/>

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/btnToMineFragment"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintTop_toBottomOf="@+id/btnToSecondFragment"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textAllCaps="false"
        android:layout_marginTop="10dp"
        android:textColor="@color/white"
        android:gravity="center"
        android:layout_margin="20dp"
        android:background="@color/design_default_color_primary"
        android:text="打开MineFragment"/>
</androidx.constraintlayout.widget.ConstraintLayout>

6.Fragment_mine布局:

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:textSize="20sp"
        tools:text="姓名"
        android:gravity="center"
        android:background="@color/design_default_color_primary"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textColor="@color/white"
        android:layout_marginTop="20dp"/>

    <TextView
        android:id="@+id/tvAge"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:textSize="18sp"
        tools:text="年龄"
        android:gravity="center"
        android:background="@color/design_default_color_primary"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tvTitle"
        android:textColor="@color/white"
        android:layout_marginTop="20dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

7.Fragment_second布局:

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:textSize="20sp"
        tools:text="姓名"
        android:gravity="center"
        android:background="@color/design_default_color_primary"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textColor="@color/white"
        android:layout_marginTop="20dp"/>

    <TextView
        android:id="@+id/tvAge"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:textSize="18sp"
        tools:text="年龄"
        android:gravity="center"
        android:background="@color/design_default_color_primary"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tvTitle"
        android:textColor="@color/white"
        android:layout_marginTop="20dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

8.activity_main主界面:

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_wallpaper"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="2dp"
        android:paddingEnd="2dp"
        android:visibility="gone" />

    <ProgressBar
        android:id="@+id/pb_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/btn_get_wallpaper"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:text="获取壁纸"
        android:textColor="@color/white"
        android:gravity="center"
        android:background="@color/design_default_color_primary"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="20dp"/>
    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_get_wallpaper"
        app:navGraph="@navigation/nav_graph"
        android:layout_marginTop="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

9.MainActivity代码:

kotlin 复制代码
package com.cloud.flowbusdemo

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.LogUtils
import com.cloud.flowbusdemo.databinding.ActivityMainBinding
import com.cloud.flowbusdemo.flow.FlowBus
import com.cloud.flowbusdemo.http.HttpUtils
import com.cloud.flowbusdemo.intent.MainIntent
import com.cloud.flowbusdemo.model.MessageEvent
import com.cloud.flowbusdemo.service.FlowBusTestService
import com.cloud.flowbusdemo.ui.adapter.WallpaperAdapter
import com.cloud.flowbusdemo.ui.viewmodel.MainViewModel
import com.cloud.flowbusdemo.ui.viewmodel.ViewModelFactory
import com.cloud.flowbusdemo.uistate.MainUIState
import com.cloud.flowbusdemo.utils.CToast
import com.cloud.flowbusdemo.utils.GenericToast
import com.cloud.flowbusdemo.utils.SingleToast
import kotlinx.coroutines.launch


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    private lateinit var mainViewModel: MainViewModel

    private var wallPaperAdapter = WallpaperAdapter(arrayListOf())
    private val TAG = "flowBusDemo"

    private var mCToast: CToast? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        mainViewModel = ViewModelProvider(
            this,
            ViewModelFactory(HttpUtils.apiService)
        )[MainViewModel::class.java]
        initView()
        observeViewModel()
        initService()
    }

    private fun initService() {
        val intent = Intent(this@MainActivity, FlowBusTestService::class.java)
        intent.putExtra("sockUrl","")
        startService(intent)
    }

    /**
     * ViewModel
     */
    @SuppressLint("NotifyDataSetChanged")
    private fun observeViewModel() {
        lifecycleScope.launch {
            mainViewModel.state.collect {
                when (it) {
                    is MainUIState.Idle -> {

                    }

                    is MainUIState.Loading -> {
                        binding.btnGetWallpaper.visibility = View.GONE
                        binding.pbLoading.visibility = View.VISIBLE
                    }

                    is MainUIState.Success -> {     //数据返回
                        binding.btnGetWallpaper.visibility = View.GONE
                        binding.pbLoading.visibility = View.GONE

                        binding.rvWallpaper.visibility = View.VISIBLE
                        it.wallpaper.let { paper ->
                            wallPaperAdapter.addData(paper.res.vertical)
                        }
                        wallPaperAdapter.notifyDataSetChanged()
                    }

                    is MainUIState.Error -> {
                        binding.pbLoading.visibility = View.GONE
                        binding.btnGetWallpaper.visibility = View.VISIBLE
                        Log.d("TAG", "observeViewModel: $it.error")
                        Toast.makeText(this@MainActivity, it.error, Toast.LENGTH_LONG).show()
                    }
                }
            }
        }
    }

    /**
     * 初始化
     */
    private fun initView() {
        binding.rvWallpaper.apply {
            layoutManager = GridLayoutManager(this@MainActivity, 2)
            adapter = wallPaperAdapter
        }
        binding.btnGetWallpaper.setOnClickListener {
           lifecycleScope.launch {
                mainViewModel.mainIntentChannel.send(MainIntent.GetWallpaper)
            }
            val intent = Intent(this@MainActivity,TestActivity::class.java)
            startActivity(intent)


            val timeToast =
                SingleToast.makeText(this@MainActivity, "显示时间自定的Toast", 10.0)
            timeToast.show()
        }
        FlowBus.with<MessageEvent>("test").register(this@MainActivity) {
            LogUtils.d(TAG,it.toString())
            if(it.message == "stop"){
                LogUtils.d(TAG,"===接收到的消息为==="+it.message)
            }
        }
        FlowBus.with<MessageEvent>("mineFragment").register(this@MainActivity) {
            LogUtils.d(TAG,it.toString())
            if(it.message == "onMine"){
                LogUtils.d(TAG,"===接收到的消息为1111==="+it.message)
            }
        }
    }
}

10.MainFragment代码:

复制代码
package com.cloud.flowbusdemo.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import com.cloud.flowbusdemo.R
import com.cloud.flowbusdemo.databinding.FragmentMainBinding

private const val ARG_PARAM_NAME = "name"
private const val ARG_PARAM_AGE = "age"

/**
 * @auth: njb
 * @date: 2024/9/17 18:46
 * @desc: 描述
 */
class MainFragment : Fragment() {
    private lateinit var binding: FragmentMainBinding
    private var name: String? = null
    private var age: Int? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            name = it.getString(ARG_PARAM_NAME)
            age = it.getInt(ARG_PARAM_AGE)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentMainBinding.inflate(layoutInflater)
        initView()
        return binding.root
    }

    private fun initView() {
        binding.btnToSecondFragment.setOnClickListener(View.OnClickListener { v ->
            /*      val bundle = Bundle()
                  bundle.putString("name", "Michael")
                  bundle.putInt("age", 30)*/
            val args: Bundle = Bundle().apply {
                this.putString(ARG_PARAM_NAME, "哈哈")
                this.putInt(ARG_PARAM_AGE, 25)
            }
            Navigation.findNavController(v)
                .navigate(R.id.action_mainFragment_to_secondFragment, args)
        })
        binding.btnToMineFragment.setOnClickListener{v ->
            val args: Bundle = Bundle().apply {
                this.putString(ARG_PARAM_NAME, "Tom")
                this.putInt(ARG_PARAM_AGE, 18)
            }
            val navController = Navigation.findNavController(v)
            //navController.navigate(R.id.action_mainFragment_to_mineFragment, args)
            val bundle: Bundle = MainFragmentArgs("haha",20).toBundle()
             Navigation.findNavController(v).navigate(R.id.action_mainFragment_to_mineFragment,bundle)
        }
    }


}

11.MineFragment代码:

kotlin 复制代码
package com.cloud.flowbusdemo.fragment

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs
import com.cloud.flowbusdemo.databinding.FragmentMineBinding
import com.cloud.flowbusdemo.flow.FlowBus
import com.cloud.flowbusdemo.model.MessageEvent
import kotlinx.coroutines.launch

private const val ARG_PARAM_NAME = "name"
private const val ARG_PARAM_AGE = "age"
/**
 * @auth: njb
 * @date: 2024/9/17 19:43
 * @desc: 描述
 */
class MineFragment :Fragment(){
    private lateinit var binding: FragmentMineBinding
    private val TAG = "MineFragment"
    private var name: String? = null
    private var age: Int? = 0
    private val args:MainFragmentArgs by  navArgs()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        args.let {
            name = args.name
            age = args.age
        }

        Log.i(TAG, "传递过来的参数为 name = $name , age = $age")
        Log.d(TAG, "姓名:" + name + "年龄:" + age)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentMineBinding.inflate(layoutInflater)
        initView()
        return binding.root
    }


    private fun initView() {
        val messageEvent = MessageEvent()
        messageEvent.message = "onMine"
        messageEvent.state = false
        binding.let {
            it.tvTitle.text = name
            it.tvAge.text  = age.toString()
            it.tvTitle.setOnClickListener {
                lifecycleScope.launch {
                    FlowBus.with<MessageEvent>("mineFragment").post(this, messageEvent)
                }
            }
        }
    }
}

12.SecondFragment代码:

kotlin 复制代码
package com.cloud.flowbusdemo.fragment

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.cloud.flowbusdemo.constants.Constants
import com.cloud.flowbusdemo.databinding.FragmentMineBinding
import com.cloud.flowbusdemo.databinding.FragmentSecondBinding
import com.cloud.flowbusdemo.flow.FlowBus
import com.cloud.flowbusdemo.model.MessageEvent
import kotlinx.coroutines.launch

/**
 * @auth: njb
 * @date: 2024/9/17 18:48
 * @desc: 描述
 */
class SecondFragment : Fragment(){
    private val TAG = "SecondFragment"
    private var name: String? = null
    private var age: Int? = null
    private lateinit var binding: FragmentSecondBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentSecondBinding.inflate(layoutInflater)
        initView()
        return binding.root
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            name = it.getString(Constants.ARG_PARAM_NAME)
            age = it.getInt(Constants.ARG_PARAM_AGE)
        }
        Log.i(TAG, "MainFragment 传递到 SecondFragment 的参数为 name = $name , age = $age")
        Log.d(TAG, "姓名:" + name + "年龄:" + age)
    }

    private fun initView() {
        binding.let {
            it.tvTitle.text = name
            it.tvAge.text  = age.toString()
        }
    }
}

13.传递参数的方式:

13.1使用bundle:

kotlin 复制代码
binding.btnToSecondFragment.setOnClickListener(View.OnClickListener { v ->
          val bundle = Bundle()
          bundle.putString("name", "Michael")
          bundle.putInt("age", 30)
    Navigation.findNavController(v)
        .navigate(R.id.action_mainFragment_to_secondFragment, bundle)
})

13.2使用Safs安全方式传递:

kotlin 复制代码
binding.btnToMineFragment.setOnClickListener{v ->
    val bundle: Bundle = MainFragmentArgs("haha",20).toBundle()
     Navigation.findNavController(v).navigate(R.id.action_mainFragment_to_mineFragment,bundle)
}

14.实现效果如下:

15.项目demo地址:

https://gitee.com/jackning_admin/flowbus-demo

相关推荐
fangzhanpeng1684 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心6 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552712 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552712 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝14 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552714 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552714 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552717 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552717 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552718 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节