Android Fragment数据传递异常:NgoSignup2Fragment获值为Null
Fragment间数据传递为空问题排查
问题描述
尝试从NgoSignup1Fragment向NgoSignup2Fragment传递数据,MainActivity通过Communicator接口接收数据时变量值均正确,但NgoSignup2Fragment中获取到的所有变量值均为Null。
相关代码
NgoSignup1Fragment代码
class NgoSignup1Fragment : Fragment() { private lateinit var communicator: Communicator private lateinit var nextBtn: Button private var name : TextInputEditText ?=null private var mail : TextInputEditText ?=null private var phone : TextInputEditText ?=null private var add :TextInputEditText ?=null private var pinCode :TextInputEditText ?=null private var password :TextInputEditText ?=null private var confirmPassword :TextInputEditText ?=null private val emailPattern = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+" override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View? { val v = layoutInflater.inflate(R.layout.ngo_signup1_fragment, container, false) communicator = activity as Communicator nextBtn = v.findViewById(R.id.btn_ngosignup1_next) name = v?.findViewById(R.id.et_ngosignup_name) mail = v?.findViewById(R.id.et_ngosignup_mail) phone = v?.findViewById(R.id.et_ngosignup_phone) add = v?.findViewById(R.id.et_ngosignup_address) pinCode = v?.findViewById(R.id.et_ngosignup_pincode) password =v?.findViewById(R.id.et_ngosignup_password) confirmPassword =v?.findViewById(R.id.et_ngosignup_confirmpassword) nextBtn.setOnClickListener { val orgName = name?.text.toString().trim() val orgMail = mail?.text.toString().trim() val orgPhone = phone?.text.toString().trim() val officeAdd = add?.text.toString().trim() val orgPinCode = pinCode?.text.toString().trim() val orgPass = password?.text.toString().trim() val confirmPass=confirmPassword?.text.toString().trim() if (orgName.isEmpty()) { name?.error = "Please provide organisation's name" markButtonDisable(nextBtn) } if (orgMail.isEmpty()) { mail?.error = "Mail cannot be empty" markButtonDisable(nextBtn) } if (orgPhone.isEmpty()) { phone?.error = "Enter your phone number" markButtonDisable(nextBtn) } if (officeAdd.isEmpty()) { add?.error = "Address cannot be empty" markButtonDisable(nextBtn) } if (orgPinCode.isEmpty()) { name?.error = "Name cannot be empty" markButtonDisable(nextBtn) } if (orgPass.isEmpty()){ password?.error = "Password cannot be empty" markButtonDisable(nextBtn) } if (!(orgMail.matches(emailPattern.toRegex()))) { mail?.error = "Invalid email" markButtonDisable(nextBtn) } if (!(isValidPassword(orgPass))) { password?.error = "Password format is invalid" markButtonDisable(nextBtn) } if(orgPass != confirmPass){ confirmPassword?.error = "Passwords doesn't match" markButtonDisable(nextBtn) }else{ communicator.passDataCom(orgName,orgMail,orgPhone,officeAdd,orgPinCode,orgPass) activity?.supportFragmentManager?.beginTransaction() ?.replace( R.id.fragment_container1, NgoSignup2Fragment() )?.addToBackStack(null)?.commit() } } return v } private fun isValidPassword(password: String): Boolean { val passwordREGEX = Pattern.compile( "^" + "(?=.*[0-9])" + //at least 1 digit "(?=.*[a-z])" + //at least 1 lower case letter "(?=.*[A-Z])" + //at least 1 upper case letter "(?=.*[a-zA-Z])" + //any letter "(?=.*[@#$%^&+=])" + //at least 1 special character "(?=\\S+$)" + //no white spaces ".{8,}" + //at least 8 characters "$" ) return passwordREGEX.matcher(password).matches() } private fun markButtonDisable(b:Button){ b.isEnabled =false b.setBackgroundColor(resources.getColor(R.color.theme_button_disabled)) }}
数据传递接口Communicator
interface Communicator { fun passDataCom( orgName: String, orgMail: String, orgPhone: String, officeAdd: String, orgPin: String, orgPass: String )}
MainActivity代码
class MainActivity : AppCompatActivity(),Communicator { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTheme(R.style.Theme_Samarpan) setContentView(R.layout.activity_main) addFragment() } private fun addFragment() { val userSignInLayout= LoginFragment() supportFragmentManager.beginTransaction().add(R.id.fragment_container1,userSignInLayout).commit() } override fun passDataCom( orgName: String, orgMail: String, orgPhone: String, officeAdd: String, orgPin: String, orgPass: String ) { val bundle=Bundle() bundle.putString("Name",orgName) bundle.putString("Mail",orgMail) bundle.putString("Phone",orgPhone) bundle.putString("Address",officeAdd) bundle.putString("PinCode",orgPin) bundle.putString("Password",orgPass) val transaction=this.supportFragmentManager.beginTransaction() val ngoSignUp2 = NgoSignup2Fragment() ngoSignUp2.arguments = bundle transaction. Commit() }}
接收数据的NgoSignup2Fragment代码
class NgoSignup2Fragment : Fragment(){ private var v : View?=null private var btnNgoRegister: Button?=null private var tilCategoryOthers:TextInputLayout?=null private var etCategoryOthers:TextInputEditText?=null private var orgName:String ="" private var orgMail:String ="" private var orgPhone:String ="" private var officeAdd:String ="" private var orgPin:String ="" private var orgPass:String ="" private var category:String="" private lateinit var registerAuth: FirebaseAuth override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { v = layoutInflater.inflate(R.layout.ngo_signup2_fragment,container,false) btnNgoRegister=v?.findViewById(R.id.btnNgoRegister) tilCategoryOthers=v?.findViewById(R.id.til_category_others) etCategoryOthers=v?.findViewById(R.id.et_category_others) val organisationTypes = resources.getStringArray(R.array.organisation_type) val arrayAdapter = ArrayAdapter(requireContext(),R.layout.dropdown_item,organisationTypes) val autoCompleteTV= v?.findViewById<AutoCompleteTextView>(R.id.ngosignup_select_orgtype_items) autoCompleteTV?.setAdapter(arrayAdapter) category=autoCompleteTV?.text.toString().trim() registerAuth= Firebase.auth orgName= arguments?.getString("Name").toString().trim() orgMail= arguments?.getString("Mail").toString().trim() orgPhone=arguments?.getString("Phone").toString().trim() officeAdd=arguments?.getString("Address").toString().trim() orgPin=arguments?.getString("PinCode").toString().trim() orgPass=arguments?.getString("Password").toString().trim() btnNgoRegister?.setOnClickListener { Toast.makeText(activity, orgName, Toast.LENGTH_SHORT).show() if(category == "Others"){ btnNgoRegister?.isEnabled=false tilCategoryOthers?.visibility=View.VISIBLE category=etCategoryOthers?.text.toString() btnNgoRegister?.isEnabled=true } val db = FirebaseFirestore.getInstance() try{ registerAuth.createUserWithEmailAndPassword(orgMail,orgPass) .addOnCompleteListener{ task-> if(task.isSuccessful){ val ngo: FirebaseUser? =registerAuth.currentUser Toast.makeText( activity, "Thank You! for choosing us", Toast.LENGTH_SHORT ).show() val documentReference : DocumentReference =db.collection("users").document( ngo?.uid ?: "" ) val ngoInfo :MutableMap<String,Any> = HashMap() ngoInfo["Full Name"]= orgName ngoInfo["Email"]= orgMail ngoInfo["PhoneNumber"]=orgPhone ngoInfo["Address"]=officeAdd ngoInfo["Pin Code"]=orgPin ngoInfo["isDonor"]="0" documentReference.set(ngoInfo).addOnSuccessListener { Log.d(ContentValues.TAG, "User data for $orgName was collected successfully ") }.addOnFailureListener{ e -> Log.w(ContentValues.TAG, "Error adding data", e) } }else{ Toast.makeText( activity, task.exception!!.message.toString(), Toast.LENGTH_SHORT ).show() } } } catch(e :Exception){ Toast.makeText(context, "Fields cannot be empty $e", Toast.LENGTH_SHORT).show() } } return v }}
问题原因
核心问题在于两次创建了不同的NgoSignup2Fragment实例:
MainActivity的passDataCom方法中,创建了绑定数据的NgoSignup2Fragment实例,但仅调用了拼写错误的transaction.Commit()(应为小写commit()),未执行replace操作将该实例加载到容器。NgoSignup1Fragment的按钮点击事件里,又新建了一个无数据绑定的NgoSignup2Fragment实例并执行替换,导致接收端获取不到数据。
修复方案
方案一:让MainActivity负责Fragment替换
- 更新
MainActivity的passDataCom方法,完成替换逻辑:
override fun passDataCom( orgName: String, orgMail: String, orgPhone: String, officeAdd: String, orgPin: String, orgPass: String ) { val bundle=Bundle() bundle.putString("Name",orgName) bundle.putString("Mail",orgMail) bundle.putString("Phone",orgPhone) bundle.putString("Address",officeAdd) bundle.putString("PinCode",orgPin) bundle.putString("Password",orgPass) val ngoSignUp2 = NgoSignup2Fragment() ngoSignUp2.arguments = bundle supportFragmentManager.beginTransaction() .replace(R.id.fragment_container1, ngoSignUp2) .addToBackStack(null) .commit() }
- 修改
NgoSignup1Fragment的按钮点击逻辑,移除自行创建Fragment的代码:
else{ communicator.passDataCom(orgName,orgMail,orgPhone,officeAdd,orgPinCode,orgPass) // 移除以下代码 // activity?.supportFragmentManager?.beginTransaction() // ?.replace( // R.id.fragment_container1, // NgoSignup2Fragment() // )?.addToBackStack(null)?.commit() }
方案二:直接在NgoSignup1Fragment中传递数据
若无需MainActivity处理数据,可直接在NgoSignup1Fragment中完成数据传递与Fragment替换,简化流程:
else{ val bundle=Bundle() bundle.putString("Name",orgName) bundle.putString("Mail",orgMail) bundle.putString("Phone",orgPhone) bundle.putString("Address",officeAdd) bundle.putString("PinCode",orgPinCode) bundle.putString("Password",orgPass) val ngoSignUp2 = NgoSignup2Fragment() ngoSignUp2.arguments = bundle activity?.supportFragmentManager?.beginTransaction() ?.replace(R.id.fragment_container1, ngoSignUp2) ?.addToBackStack(null) ?.commit() }
此方案可同步移除Communicator接口及MainActivity中的对应实现代码。
内容的提问来源于stack exchange,提问作者Jadu
相关产品推荐
相关产品推荐

