尝试使用 Kotlin 和 onActivityResult 将数据从 Fragment 发送到 Activity

Posted

技术标签:

【中文标题】尝试使用 Kotlin 和 onActivityResult 将数据从 Fragment 发送到 Activity【英文标题】:trying to send data from a Fragment to an Activity with Kotlin and onActivityResult 【发布时间】:2021-06-07 03:43:30 【问题描述】:

当在 MainActivity.kt 中按下“添加客户”按钮时,会为 Result CustomerActivity.kt 启动一个新 Activity。 CustomerActivity 打开 Fragment (ListFragment.kt),其中包含 Room 数据库中所有客户的列表。

点击客户时,会打开另一个片段。在 UpdateFragment.kt 中,显示了所有客户信息和一个“选择客户”按钮。单击后,将创建一个 Intent,并将客户信息添加到 Intent。再次打开 Main Activity,并在 Intent 中传递选定的客户信息。

如何从 MainActivity.kt 中的 UpdateFragment.kt 打开 Intent 以获取其信息?并获得对有意传递的客户信息的访问权限?目前,我可以使用 UpdateFragment.kt 中的客户信息创建意图并打开 MainActivity.kt,但我不知道如何访问 MainActivity 中的意图。

MainActivity.kt

package com.example.app

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.multiplerecyclerview.CustomerAdapter
import kotlinx.android.synthetic.main.activity_customer.*

const val INDEX = 0

class MainActivity : AppCompatActivity() 

    val list = ArrayList<DataModel>() /*ArrayList that is type Data Model. */

    /* Adapter class is initialized and list is passed in the param. */
    val customerAdapter = CustomerAdapter(this, getItemsList())

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        customerButton.setOnClickListener  /* Customer onclick button: Gets taken to the customer screen. */
            val intent = Intent(this@MainActivity, CustomerActivity::class.java)  /* Creating an Intent to go to Customer Activity so a customer can be selected. */
            startActivityForResult(intent,1) /* Starting Activity for result. */
        

        /* Set the LayoutManager that this RecyclerView will use. */
        customerRecyclerView.layoutManager = LinearLayoutManager(this)

        /* Adapter instance is set to the recyclerview to inflate the items. */
        customerRecyclerView.adapter = customerAdapter

    

    /* This function is invoked once we return from Activity. */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == 1) 
            val name: String = data?.getStringExtra("customerName").toString() /* storing the values from arguments returned. */
            val number: String = data?.getStringExtra("customerNumber").toString()
            val postalCode: String = data?.getStringExtra("postalCode").toString()
            val address: String = data?.getStringExtra("address").toString()

        

    

    private fun getItemsList(): ArrayList<DataModel> 

        list.add(DataModel("Todd Philips","123 Fake Street","012801212", OrderAdapter.CUSTOMER_ADD))

        return list
    


CustomerActivity.kt

package com.example.app

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class CustomerActivity : AppCompatActivity() 

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_customer)
    


activity_customer.xml

<?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_
    android:layout_
    tools:context=".CustomerActivity">

    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_
        android:layout_
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/app_nav" />

</androidx.constraintlayout.widget.ConstraintLayout>

ListFragment.kt

package com.example.app

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.app.viewmodel.AppViewModel
import com.example.app.fragments.list.ListAdapter
import kotlinx.android.synthetic.main.fragment_list.view.*

class listFragment : Fragment() 

    private lateinit var appViewModel: appViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_list, container, false)
        //val search = findViewById<>

        // RecyclerView
        val adapter = ListAdapter()
        val recyclerView = view.recyclerview
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(requireContext())

        //CustomerViewModel
        appViewModel = ViewModelProvider(this).get(AppViewModel::class.java)
        appViewModel.readAllData.observe(viewLifecycleOwner, Observer customer ->
            adapter.setData(customer)
        )


        view.floatingActionButton.setOnClickListener 
            findNavController().navigate(R.id.action_listFragment_to_addFragment)
        
        return view
    

UpdateFragment.kt

package com.example.app.fragments.update

import android.content.Intent
import androidx.appcompat.app.AlertDialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.widget.AlertDialogLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.example.app.*
import com.example.app.model.Customer
import com.example.app.viewmodel.APPViewModel
import kotlinx.android.synthetic.main.fragment_update.*
import kotlinx.android.synthetic.main.fragment_update.view.*

class UpdateFragment : Fragment() 

    private val args by navArgs<UpdateFragmentArgs>()
    private lateinit var appViewModel: APPViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_update, container, false)

        appViewModel = ViewModelProvider(this).get(APPViewModel::class.java)

        view.updateTextName.setText(args.currentCustomer.name)
        view.updateTextNumber.setText(args.currentCustomer.mobile)
        view.updatePostalAddress.setText(args.currentCustomer.eircode)
        view.updateTextAddress.setText(args.currentCustomer.address)

        view.updateBtn.setOnClickListener 
            updateItem()
        

        view.deleteBtn.setOnClickListener 
            deleteItem()
        

        view.pickBtn.setOnClickListener 
            val name = updateTextName.text.toString()
            val number = updateTextNumber.text.toString()
            val postalCode = updatePostalAddress.text.toString()
            val address = updateTextAddress.text.toString()

            Toast.makeText(requireContext(), "Pick Button Clicked!", Toast.LENGTH_SHORT).show()
           //val intent = Intent(getActivity(), OrderActivity::class.java)
           
            //Creating the intent to return to MainActivity with customer information
            val intent = Intent(activity, MainActivity::class.java)
            activity?.startActivity(intent)

            intent.putExtra("customerName", name)
            intent.putExtra("customerNumber", number)
            intent.putExtra("postalCode", postalCode)
            intent.putExtra("address", address)

            activity?.startActivity(intent)


           // setResult(RESULT_CODE_2, intent) // Tried using this code to finish the activity and return to main
           // finish() /* Ending the  Activity. */
        

        return view
    

    private fun updateItem() 
        val name = updateTextName.text.toString()
        val number = updateTextNumber.text.toString()
        val postalCode = updatePostalAddress.text.toString()
        val address = updateTextAddress.text.toString()

        val customer = Customer(args.currentCustomer.id, name,address,postalCode,number)

        posViewModel.updateCustomer(customer)
        Toast.makeText(requireContext(), "Successfully updated!", Toast.LENGTH_LONG).show()
        // Returning to the List Fragment
        findNavController().navigate(R.id.action_updateFragment_to_listFragment)

    

    private fun deleteItem() 
       
    




在 MainActivity 中点击了此按钮

更新

我在UpdateFragment.kt,我想创建一个关于客户的意图和附加信息,并将附加信息发送到MainActivity.kt

问题在于接收发送到 MainActivity 的信息。我在 MainActivity 中使用 onActivityResult 来接收来自 UpdateFragment 的意图。但是该函数没有被调用。 UpdateFragment.kt

    view.pickBtn.setOnClickListener 
            val name = updateTextName.text.toString()
            val number = updateTextNumber.text.toString()
            val postalCode = updatePostalAddress.text.toString()
            val address = updateTextAddress.text.toString()

            Toast.makeText(requireContext(), "Pick Button Clicked!", Toast.LENGTH_SHORT).show()
           //val intent = Intent(getActivity(), MainActivity::class.java)
       /*
            val intent = Intent(activity, MainActivity::class.java)

            intent.putExtra("customerName", name)
            intent.putExtra("customerNumber", number)
            intent.putExtra("postalCode", postalCode)
            intent.putExtra("address", address)

            activity?.startActivity(intent)
*/
            startActivityForResult(Intent(context, OrderActivity::class.java), 141)

           // setResult(RESULT_CODE_2, intent)
           // finish() /* Ending the  Activity. */
        

        return view
    

    override fun startActivityForResult(intent: Intent?, requestCode: Int) 

        if (requestCode == 141) 
            intent!!.putExtra("customerName", "John")
            intent.putExtra("customerNumber", "087212")
            intent.putExtra("postalCode", "V1H7")
            intent.putExtra("address", "123 Fake Street")

            onActivityResult(1, 2, intent)
        

    

MainActivity.kt


/* This function is invoked once we return from Activity. */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)

       
            val name: String = data?.getStringExtra("customerName").toString() /* storing the values from arguments returned. */
            val number: String = data?.getStringExtra("customerNumber").toString()
            val postalCode: String = data?.getStringExtra("postalCode").toString()
            val address: String = data?.getStringExtra("address").toString()

    

【问题讨论】:

你不应该开始你的 MainActivity,而是完成当前的一个,并按照注释代码设置结果并检查 requestCode。 您好 hardatcore,我收到错误 Unresolved reference: setResult in UpdateFragment.kt。对于finish() 也一样。如果此代码有效,它会将结果带回片段 ListFragment,然后需要另一个 finish() 将结果发送回 MainActivity。 你应该使用activity.setResult() / activity.finish()。但是我在您的代码中看到您正在使用Navigation lib,如果您的整个导航都基于此,我认为您应该继续使用该库来获取onActivityResult 如何使用 onActivityResult,我在问题的底部留下了一个更新,只是为了满足我的要求。 你想使用导航库还是不使用它? 【参考方案1】:

我没有阅读您编写的所有内容,但是在您的 Activity 类中,您正在检查错误的结果代码。改成请求码

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
    super.onActivityResult(requestCode, resultCode, data)

    if (resultCode == RESULT_OK) 
        if (requestCode== 1) 
           val name: String = data?.getStringExtra("customerName").toString() /* storing the values from arguments returned. */
           val number: String = data?.getStringExtra("customerNumber").toString()
           val postalCode: String = data?.getStringExtra("postalCode").toString()
           val address: String = data?.getStringExtra("address").toString()
        
    

【讨论】:

我更改了代码,但我认为 Main 中的 onActivityResult 没有被打开,因为我在 UpdateFragment 中设置了意图(有没有办法添加请求代码并让 onActivityResult 被调用来自更新片段?):val intent = Intent(activity, OrderActivity::class.java) activity?.startActivity(intent) intent.putExtra("customerName", name) activity?.startActivity(intent)【参考方案2】:

抱歉,没有完整检查代码,但为了您的预期结果,您可以试试这个:

从你的 UpdateFragment 打开 MainActivity ->

您需要从片段本身执行 startActivityForResult。不要使用活动?.startActivity()。使用UpdateFragment的startActivityForResult,可以在UpdateFragment本身实现onActivityResult(),在调用setResult()和finish()时从MainActivity中获取结果。

编辑: 我的意思是从片段开始活动并在片段本身中实现 ​​onActivityResult。这样,您的活动将从片段开始,一旦完成,就会将结果提供给片段。

UpdateFragment.kt

view.pickBtn.setOnClickListener 
        val name = updateTextName.text.toString()
        val number = updateTextNumber.text.toString()
        val postalCode = updatePostalAddress.text.toString()
        val address = updateTextAddress.text.toString()

        Toast.makeText(requireContext(), "Pick Button Clicked!", Toast.LENGTH_SHORT).show()
       //val intent = Intent(getActivity(), MainActivity::class.java)
   
        val intent = Intent(activity, MainActivity::class.java)

        intent.putExtra("customerName", name)
        intent.putExtra("customerNumber", number)
        intent.putExtra("postalCode", postalCode)
        intent.putExtra("address", address)

        //activity?.startActivity(intent)

        startActivityForResult(intent, 141)

       // setResult(RESULT_CODE_2, intent)
       // finish() /* Ending the  Activity. 
    

    return view


/* This function is invoked once we return from Activity. */
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
            super.onActivityResult(requestCode, resultCode, data)
            val name: String = data?.getStringExtra("customerName").toString() /* storing the values from arguments returned. */
        val number: String = data?.getStringExtra("customerNumber").toString()
        val postalCode: String = data?.getStringExtra("postalCode").toString()
        val address: String = data?.getStringExtra("address").toString()


在您的主要活动中,覆盖 onActivityResult 并调用 super()。

MainActivity.kt:

/* This function is invoked once we return from Activity. */
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
//The activity gets the first shot at onActivityResult. 
//If we don't want to do any process here, then we need to call super.onActivityResult() 
//which will then allow the fragment's onActivityResult to be called. 
//This ONLY works when we start the activity from the fragment.
        super.onActivityResult(requestCode, resultCode, data)
    

如果你愿意,可以参考这个答案here获取片段中的onActivityResult回调。

【讨论】:

嗨,Rishabh,您能否查看问题底部的更新。我尝试实现此功能,但无法使代码正常工作。 嘿,请检查我编辑的答案。让我知道事情的进展!抱歉回复晚了……

以上是关于尝试使用 Kotlin 和 onActivityResult 将数据从 Fragment 发送到 Activity的主要内容,如果未能解决你的问题,请参考以下文章

为什么我们要尝试Kotlin

尝试创建 OkHttpClient 对象时出现 kotlin/TypeCastException

Firebase Android -- 在 Kotlin 中使用电子邮件和密码创建用户

尝试使用意图发送电子邮件时崩溃(Kotlin)

Kotlin 和 Java 中的 RuntimeException 和 GraphQLError

尝试用kotlin做一个app