Kotlin Android Jetpack Navigation between fragments in backstack
Kotlin Android Jetpack Navigation between Fragments in backstack
我有一个小应用程序。 1 Activity (MainActivity.kt) 和两个片段 (MainFragment & CreateNewJobFragment)。
Mainfragment 有一个 Recyclerview。 CreateNewJobFragment 包含一个 6 个微调器和一个编辑文本。当用户做出选择并单击“创建作业”按钮时,我试图从微调器和编辑文本中进行选择以填充 RecyclerView。
问题是,单击此按钮时,应用程序将返回到 MainFragment 的后台堆栈,但它不会使用新项目填充 recyclerview,而是再次运行 onCreate 并且没有任何反应。
MainFragment.kt
class MainFragment : Fragment() ,ItemClickedCustomListener{
override fun onCustomSpinnerItemSelected(selectedItems: JobData) {
Log.v("MainFragment","onCustomSpinnerItemSelected")
Log.v("MainFragment","selectedItems --> "
+ selectedItems.companyName + " "
+ selectedItems.location + " "
+ selectedItems.pumpTruck + " "
+ selectedItems.smartPiggers)
jobs.add(selectedItems)
adapter = recyclerView.adapter as JobAdapter
adapter.data(jobs)
}
var jobs = ArrayList<JobData>()
lateinit var adapter : JobAdapter
private lateinit var binding: FragmentMainBinding
lateinit var recyclerView : RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (savedInstanceState == null) {
binding = FragmentMainBinding.inflate(inflater)
//getting recyclerview from xml and binding it
recyclerView = binding.jobRecyclerView
//adding a layoutmanager
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
//Arraylist to store jobs using the data class JobData.
// TODO: Change this to a user created list from CreateNewJobFragment.kt
jobs = ArrayList()
Log.v("MainFragment", "onCreateView --> ")
//creating adapter
adapter = JobAdapter(jobs)
//add adapter to recyclerView
recyclerView.adapter = adapter
//Setting onClickListener for FAB(floating action button) using Navigation
binding.createNewJobFAB.setOnClickListener { v: View ->
v.findNavController().navigate(R.id.action_mainFragment_to_createNewJobFragment)
}
}
return binding.root
}
}
CreateNewJobFragment.kt
class CreateNewJobFragment : Fragment() {
private lateinit var binding: FragmentCreateNewJobBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentCreateNewJobBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var addJobToRecyclerview = JobData("","","","")
//String array.
//TODO: Move this to res/strings
val companyNames = arrayOf("Company A", "Company B", "Company C", "Company D", "Company E")
var nameSpinner = binding.spinnerCustomerName
//Adapter for spinner
nameSpinner.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_dropdown_item, companyNames)
//item selected listener for spinner
nameSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(p0: AdapterView<*>?) {
TODO("not implemented yet")
}
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
//user selected spinner choice added
addJobToRecyclerview.companyName = companyNames[p2]
}
}
//String array.
//TODO: Move this to res/strings
val refineryTown = arrayOf("Long Beach", "Houston", "Cherry Point", "Wood River", "Bismark")
var townSpinner = binding.spinnerLocation
//Adapter for spinner
townSpinner.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_dropdown_item, refineryTown)
//item selected listener for spinner
townSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(p0: AdapterView<*>?) {
TODO("not implemented yet")
}
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
addJobToRecyclerview.location = refineryTown[p2]
}
}
<SNIP>Cutting out 5 repeated spinners and editText to save some space</SNIP>
//Setting onClickListener for 'Create Job' button using Navigation
binding.buttonCreateJob.setOnClickListener { v: View ->
(activity as MainActivity).itemClickedCustomListener.onCustomSpinnerItemSelected(addJobToRecyclerview)
Log.v("CreateNewJobFragment", "Job data added -->$addJobToRecyclerview")
Log.v("CreateNewJobFragment", "Create job button --> clicked")
v.findNavController().navigate(R.id.action_createNewJobFragment_to_mainFragment)
}
}
}
我使用以下 Android 文档作为指南:Implementing Navigation
这部分特别用于返回 MainFragment 的导航:Tie destinations to UI widgets
点击“创建任务”按钮后。 App 确实返回到 MainFragment。但如前所述,Recyclerview 中没有显示任何内容。
我已经准备好了一些日志记录。这是来自日志:
日志样本
2018-12-07 22:03:17.959 5806-5806/com.palarran.pigtimer V/MainActivity: onCustomSpinnerItemSelected
2018-12-07 22:03:17.959 5806-5806/com.palarran.pigtimer V/MainActivity: selectedItems --> Company A Long Beach Company 1 Company 4
2018-12-07 22:03:17.960 5806-5806/com.palarran.pigtimer V/CreateNewJobFragment: Job data added -->JobData(companyName=Company A, location=Long Beach, pumpTruck=Company 1, smartPiggers=Company 4)
2018-12-07 22:03:17.960 5806-5806/com.palarran.pigtimer V/CreateNewJobFragment: Create job button --> clicked
2018-12-07 22:03:18.026 5806-5806/com.palarran.pigtimer V/MainFragment: onCreateView -->
2018-12-07 22:03:18.146 5806-5806/com.palarran.pigtimer V/JobAdapter: getItemCount 0
2018-12-07 22:03:18.146 5806-5806/com.palarran.pigtimer V/JobAdapter: getItemCount 0
如您所见,在“创建作业按钮 --> 单击”的日志条目之后,它跳转到 MainFragment 中的“onCreateView”,我的自定义适配器中的项目计数 (JobAdapter.kt)不增加。
JobAdapter.kt
class JobAdapter(private var jobList: ArrayList<JobData>) : RecyclerView.Adapter<JobAdapter.ViewHolder>() {
//Returning view for each item in the list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JobAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.job_list_item, parent, false)
Log.v("JobAdapter","onCreateViewHolder")
return ViewHolder(v)
}
//Binding the data on the list
override fun onBindViewHolder(holder: JobAdapter.ViewHolder, position: Int) {
Log.v("JobAdapter","onBindViewHolder")
holder.bindItems(jobList[position])
}
override fun getItemCount(): Int {
Log.v("JobAdapter","getItemCount " + jobList.size)
return jobList.size
}
fun data(jobs: ArrayList<JobData>) {
Log.v("JobAdapter","DataSetChanged")
jobList = jobs
notifyDataSetChanged()
}
//Class holds the job list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(job: JobData) {
val textViewCompanyName = itemView.findViewById(R.id.tv_companyName) as TextView
val textViewLocation = itemView.findViewById(R.id.tv_job_location) as TextView
textViewCompanyName.text = job.companyName
Log.v("JobAdapter", "bindItems" + textViewCompanyName.text)
textViewLocation.text = job.location
Log.v("JobAdapter", "bindItems" + textViewLocation.text)
}
}
}
我是否遗漏了文档中的某些内容或阅读错误?我肯定是误会了什么。
回复晚了。
我弄明白了。通过使用 Sugar ORM 数据库。在我的 MainFragment 中的 onResume() 中调用它。
这是一个愚蠢的问题,我应该在发布之前进行更多研究。
我有一个小应用程序。 1 Activity (MainActivity.kt) 和两个片段 (MainFragment & CreateNewJobFragment)。
Mainfragment 有一个 Recyclerview。 CreateNewJobFragment 包含一个 6 个微调器和一个编辑文本。当用户做出选择并单击“创建作业”按钮时,我试图从微调器和编辑文本中进行选择以填充 RecyclerView。
问题是,单击此按钮时,应用程序将返回到 MainFragment 的后台堆栈,但它不会使用新项目填充 recyclerview,而是再次运行 onCreate 并且没有任何反应。
MainFragment.kt
class MainFragment : Fragment() ,ItemClickedCustomListener{
override fun onCustomSpinnerItemSelected(selectedItems: JobData) {
Log.v("MainFragment","onCustomSpinnerItemSelected")
Log.v("MainFragment","selectedItems --> "
+ selectedItems.companyName + " "
+ selectedItems.location + " "
+ selectedItems.pumpTruck + " "
+ selectedItems.smartPiggers)
jobs.add(selectedItems)
adapter = recyclerView.adapter as JobAdapter
adapter.data(jobs)
}
var jobs = ArrayList<JobData>()
lateinit var adapter : JobAdapter
private lateinit var binding: FragmentMainBinding
lateinit var recyclerView : RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (savedInstanceState == null) {
binding = FragmentMainBinding.inflate(inflater)
//getting recyclerview from xml and binding it
recyclerView = binding.jobRecyclerView
//adding a layoutmanager
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
//Arraylist to store jobs using the data class JobData.
// TODO: Change this to a user created list from CreateNewJobFragment.kt
jobs = ArrayList()
Log.v("MainFragment", "onCreateView --> ")
//creating adapter
adapter = JobAdapter(jobs)
//add adapter to recyclerView
recyclerView.adapter = adapter
//Setting onClickListener for FAB(floating action button) using Navigation
binding.createNewJobFAB.setOnClickListener { v: View ->
v.findNavController().navigate(R.id.action_mainFragment_to_createNewJobFragment)
}
}
return binding.root
}
}
CreateNewJobFragment.kt
class CreateNewJobFragment : Fragment() {
private lateinit var binding: FragmentCreateNewJobBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentCreateNewJobBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var addJobToRecyclerview = JobData("","","","")
//String array.
//TODO: Move this to res/strings
val companyNames = arrayOf("Company A", "Company B", "Company C", "Company D", "Company E")
var nameSpinner = binding.spinnerCustomerName
//Adapter for spinner
nameSpinner.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_dropdown_item, companyNames)
//item selected listener for spinner
nameSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(p0: AdapterView<*>?) {
TODO("not implemented yet")
}
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
//user selected spinner choice added
addJobToRecyclerview.companyName = companyNames[p2]
}
}
//String array.
//TODO: Move this to res/strings
val refineryTown = arrayOf("Long Beach", "Houston", "Cherry Point", "Wood River", "Bismark")
var townSpinner = binding.spinnerLocation
//Adapter for spinner
townSpinner.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_dropdown_item, refineryTown)
//item selected listener for spinner
townSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(p0: AdapterView<*>?) {
TODO("not implemented yet")
}
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
addJobToRecyclerview.location = refineryTown[p2]
}
}
<SNIP>Cutting out 5 repeated spinners and editText to save some space</SNIP>
//Setting onClickListener for 'Create Job' button using Navigation
binding.buttonCreateJob.setOnClickListener { v: View ->
(activity as MainActivity).itemClickedCustomListener.onCustomSpinnerItemSelected(addJobToRecyclerview)
Log.v("CreateNewJobFragment", "Job data added -->$addJobToRecyclerview")
Log.v("CreateNewJobFragment", "Create job button --> clicked")
v.findNavController().navigate(R.id.action_createNewJobFragment_to_mainFragment)
}
}
}
我使用以下 Android 文档作为指南:Implementing Navigation
这部分特别用于返回 MainFragment 的导航:Tie destinations to UI widgets
点击“创建任务”按钮后。 App 确实返回到 MainFragment。但如前所述,Recyclerview 中没有显示任何内容。
我已经准备好了一些日志记录。这是来自日志:
日志样本
2018-12-07 22:03:17.959 5806-5806/com.palarran.pigtimer V/MainActivity: onCustomSpinnerItemSelected
2018-12-07 22:03:17.959 5806-5806/com.palarran.pigtimer V/MainActivity: selectedItems --> Company A Long Beach Company 1 Company 4
2018-12-07 22:03:17.960 5806-5806/com.palarran.pigtimer V/CreateNewJobFragment: Job data added -->JobData(companyName=Company A, location=Long Beach, pumpTruck=Company 1, smartPiggers=Company 4)
2018-12-07 22:03:17.960 5806-5806/com.palarran.pigtimer V/CreateNewJobFragment: Create job button --> clicked
2018-12-07 22:03:18.026 5806-5806/com.palarran.pigtimer V/MainFragment: onCreateView -->
2018-12-07 22:03:18.146 5806-5806/com.palarran.pigtimer V/JobAdapter: getItemCount 0
2018-12-07 22:03:18.146 5806-5806/com.palarran.pigtimer V/JobAdapter: getItemCount 0
如您所见,在“创建作业按钮 --> 单击”的日志条目之后,它跳转到 MainFragment 中的“onCreateView”,我的自定义适配器中的项目计数 (JobAdapter.kt)不增加。
JobAdapter.kt
class JobAdapter(private var jobList: ArrayList<JobData>) : RecyclerView.Adapter<JobAdapter.ViewHolder>() {
//Returning view for each item in the list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JobAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.job_list_item, parent, false)
Log.v("JobAdapter","onCreateViewHolder")
return ViewHolder(v)
}
//Binding the data on the list
override fun onBindViewHolder(holder: JobAdapter.ViewHolder, position: Int) {
Log.v("JobAdapter","onBindViewHolder")
holder.bindItems(jobList[position])
}
override fun getItemCount(): Int {
Log.v("JobAdapter","getItemCount " + jobList.size)
return jobList.size
}
fun data(jobs: ArrayList<JobData>) {
Log.v("JobAdapter","DataSetChanged")
jobList = jobs
notifyDataSetChanged()
}
//Class holds the job list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(job: JobData) {
val textViewCompanyName = itemView.findViewById(R.id.tv_companyName) as TextView
val textViewLocation = itemView.findViewById(R.id.tv_job_location) as TextView
textViewCompanyName.text = job.companyName
Log.v("JobAdapter", "bindItems" + textViewCompanyName.text)
textViewLocation.text = job.location
Log.v("JobAdapter", "bindItems" + textViewLocation.text)
}
}
}
我是否遗漏了文档中的某些内容或阅读错误?我肯定是误会了什么。
回复晚了。
我弄明白了。通过使用 Sugar ORM 数据库。在我的 MainFragment 中的 onResume() 中调用它。
这是一个愚蠢的问题,我应该在发布之前进行更多研究。