繁体   English   中英

无法将数据传递给 Android (Kotlin) 中的另一个片段

[英]Can't pass data to another fragment in Android (Kotlin)

我有问题。 我正在为 MQTT 客户端的 Android 制作一个应用程序,我需要在不同的片段中为 MqttAndroidClient() 方法使用相同的参数。 我已经尝试在包中传递它们,意图是 putExtra(),制作类的对象。 bundle 和 putExtra 将数据发送到另一个片段,它在调试模式下显示,但在目标片段中我得到 nulls 当我尝试接收实例化第一个片段的值时,它向我发送了没有任何值的 lateinit 变量。 我不知道我还能做些什么。 我想过使用 setter 和 getter 来获取它,但我不确定这是解决方案。

我发送数据的第一个片段

连接片段.kt

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.dzichkovskii.mqttsrm.R
import kotlinx.android.synthetic.main.fragment_connect.*
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.io.Serializable

class ConnectFragment : Fragment(){
    companion object{
        const val SUCCESS_TEXT = "Connection established successfully"
        const val FAILURE_TEXT = "Connection wasn't established. Error happened."
        const val BLANK_TEXT = "Your inputs cannot be empty. Please, write the correct address or ID."
        const val CONNECTION_FAILURE = "Something went wrong. Probably you have no internet. Try later"
        const val SENDING_NAME_ADDRESS = "mqttAndroidClientAddress"
        const val SENDING_NAME_ID = "mqttAndroidClientId"
        const val TAG = "ConnectFragment"
    }
     lateinit var mqttAndroidClient: MqttAndroidClient

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_connect, container, false)

        //I will leave this values just in case I would need to test the connection
        //val testClientId = MqttClient.generateClientId()
        //val testAddress = "tcp://broker.hivemq.com:1883"

        root.findViewById<Button>(R.id.btn_connect).setOnClickListener {
            mqttAndroidClient = connect(context, view)

        }

        return root
    }
    private fun connect(context: Context?,
                        view: View?): MqttAndroidClient {

//        val inputAddress = view?.findViewById(R.id.tv_broker_address_input) as EditText
//        val inputId = view?.findViewById(R.id.tv_client_id_input) as EditText
//        val inputPort = view.findViewById(R.id.tv_broker_port_input) as EditText
//
        //Making the string the user needs to put more friendly
//        val addressStringSimplification = "tcp://" + inputAddress.text.toString() +
//                ":" + inputPort.text.toString()

        val addressStringSimplification = "tcp://broker.hivemq.com:1883"
        val testClientId = MqttClient.generateClientId()

        mqttAndroidClient = MqttAndroidClient(context?.applicationContext, addressStringSimplification, testClientId/*inputId.text.toString()*/)

        val intent = Intent(this.context, SubscribeFragment::class.java)

        val bundle = Bundle()
        bundle.putString("testBundle", addressStringSimplification) //bundle here
        val subscribeFragment = SubscribeFragment()
        subscribeFragment.arguments = bundle

        intent.putExtra(SENDING_NAME_ADDRESS, addressStringSimplification) //Intents here
        intent.putExtra(SENDING_NAME_ID, testClientId)

//        if (inputAddress.isBlank() || inputId.isBlank()
//            || inputPort.isBlank() || addressStringSimplification == "tcp://:"){
//           displayErrorMessage(BLANK_TEXT, view, this)
//            return
//        }
//        else {
            try {
                val token = mqttAndroidClient.connect()
                token.actionCallback = object : IMqttActionListener {
                    override fun onSuccess(asyncActionToken: IMqttToken?) {

                        Log.d(TAG, "Connection is successful")

                        Toast.makeText(context, SUCCESS_TEXT, Toast.LENGTH_SHORT).show()
                        hideKeyboard()
                        return
                    }

                    override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {

                        Log.d(TAG, "Connection didn't established")

                        Toast.makeText(context, FAILURE_TEXT, Toast.LENGTH_SHORT).show()
                        displayErrorMessage(FAILURE_TEXT, view, this@ConnectFragment)
                        return
                    }
                }
            } catch (e: MqttException) {

                Log.d(TAG, "Exception caught")

                displayErrorMessage(CONNECTION_FAILURE, view, this)
            }
        return mqttAndroidClient
    }
//        tv_error.visibility = View.INVISIBLE
    }

    /**
     * This extension function makes strings look less ugly.
     */
    private fun EditText.isBlank() = this.text.toString().isBlank()
//}

fun displayErrorMessage(errorString: String, view: View?, fragment: Fragment){
    val errorTextView = view?.rootView?.findViewById(R.id.tv_error) as TextView
    errorTextView.text = errorString
    errorTextView.visibility = View.VISIBLE
    fragment.hideKeyboard()
}

fun Fragment.hideKeyboard() {
    view?.let { activity?.hideKeyboard(it) }
}
fun Context.hideKeyboard(view: View) {
    val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
    inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
} 

这是我接收数据的另一个片段

订阅片段.kt

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.dzichkovskii.mqttsrm.R
import com.google.android.material.chip.Chip
import kotlinx.android.synthetic.main.fragment_subscribe.view.*
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.IMqttActionListener
import org.eclipse.paho.client.mqttv3.IMqttToken
import org.eclipse.paho.client.mqttv3.MqttException

class SubscribeFragment : Fragment() {

    companion object {
        const val TAG = "SubscribeFragment"
        const val BLANK_TEXT = "Your inputs cannot be empty. Please, write the correct address or ID."
        const val ON_SUCCESS = "You subscribed successfully."
        const val ON_FAILURE = "You didn't subscribed to the topic. Probably this topic doesn't exist."
        const val CONNECTION_ERROR = "The topic don't exist or you have connection problems. " +
                "Check your internet connection or change the topic's name"
        const val GETTING_NAME_ADDRESS = "mqttAndroidClientAddress"
        const val GETTING_NAME_ID = "mqttAndroidClientId"
    }

    private var checkedOption: Int = 0 //Default value of qos

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val root = inflater.inflate(R.layout.fragment_subscribe, container, false)

        return root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.chip_group?.setOnCheckedChangeListener { _, checkedId: Int ->
            val chip: Chip? = view.findViewById(checkedId)
            val qos = chip?.text.toString().toInt()
            checkedOption = qos

            Log.d(TAG, "Checked option passed with value $checkedOption")
        }

        view.findViewById<Button>(R.id.btn_subscribe).setOnClickListener {
            subscribe()
        }
    }

        private fun subscribe(){

            val connectFragment = ConnectFragment()

            val mqttAndroidClient = connectFragment.mqttAndroidClient //Instantiation of the class here

            val address = this@SubscribeFragment.arguments?.getString("testBundle") // Bundle here 
            val id = activity?.intent?.getStringExtra(GETTING_NAME_ID) // Intent string here

            //val mqttAndroidClient = MqttAndroidClient(context, address, id)

            val inputTopic = view?.findViewById(R.id.et_topic) as EditText
            val topic = inputTopic.text.toString()

            if (inputTopic.isBlank()){
                displayErrorMessage(BLANK_TEXT, view, this)
            }

            try {
                Log.d(TAG, "Checked option in subscribe method is $checkedOption")
                mqttAndroidClient.subscribe(topic, checkedOption, null, object : IMqttActionListener {
                    override fun onSuccess(asyncActionToken: IMqttToken) {
                        Toast.makeText(context, ON_SUCCESS, Toast.LENGTH_SHORT).show()
                        Log.d(TAG, "Connected successfully")
                    }
                    override fun onFailure(
                        asyncActionToken: IMqttToken,
                        exception: Throwable
                    ) {
                        Toast.makeText(context, ON_FAILURE, Toast.LENGTH_SHORT).show()
                        Log.d(TAG, "Didn't connected")
                    }
                })
            } catch (e: MqttException) {
                displayErrorMessage(CONNECTION_ERROR, view, this)
            }
        }
    private fun EditText.isBlank() = this.text.toString().isBlank()
    }

谢谢回答!

首先要创建一个片段,你应该有一个newInstance方法,这个方法应该除了你想传递给片段的参数之外,在你的情况下SubscriberFragment应该在companion object具有以下功能

class SubscribeFragment: Fragment() {
    companion object {
      const val SENDING_NAME_ADDRESS = "mqttAndroidClientAddress" 
      const val SENDING_NAME_ID = "mqttAndroidClientId"

      // Use this function to create instance of your fragment
       fun newInstance(addressStringSimplification: String,
                        testClientId: String): MyFragment {
            val args = Bundle()
            args.putString(SENDING_NAME_ADDRESS , addressStringSimplification)
            args.putString(SENDING_NAME_ID , testClientId)
            val fragment = SubscribeFragment()
            fragment.arguments = args
            return fragment
        }
    }
}

在此之后,当您的片段加载时,参数将传递给onCreate方法,您可以按如下方式提取它们。

@Override
public void onCreate(Bundle savedInstanceState) {
    var sendingName = getArguments().getInt(SENDING_NAME_ADDRESS);
    var sendingId = getArguments().getString(SENDING_NAME_ID);
}

现在到最重要的部分,您似乎认为执行SubscriberFragment()足以加载片段,但事实并非如此。 当您想启动SubscriberFragment ,您应该执行以下操作

// create instance of SubscriberFragment with newInstance function and pass the argguments you want
var someFragment = SubscribeFragment.newInstance(addressStringSimplification,testClientId);
var transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, someFragment); // give your fragment container id in first parameter
    transaction.addToBackStack(null);  
    transaction.commit(); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM