Android在kts中使用navigation及Args的方法
作者:淡淡的香烟
在Android项目中使用Kotlin脚本(kts)替代Groovy配置navigation和Args,需添加相关依赖,并在build.gradle中进行配置,文章详细介绍了如何在kts中使用navigation进行页面导航和参数传递,介绍了使用Bundle和Safe 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配置:
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配置:
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文件
<?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
<?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布局:
<?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布局:
<?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主界面:
<?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代码:
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代码:
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代码:
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:
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安全方式传递:
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
到此这篇关于Android在kts中使用navigation及Args的文章就介绍到这了,更多相关Android 使用navigation Args内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!