Kotlin android data transfer from fragment to dialogFragment - android

I want to pass some data from Fragment to a DialogFragment (when I click a view by using onClickListener), but the data has empty values in Dialog.
While debugging I found that VO data has no problem. (log comments in my code works correctly)
So, I think that I am not using Bundle correctly.
What can I do to solve this problem?
AccountFragment.class (recyclerview bindViewHolder)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val accountVO = list[position]
val viewHolder = holder as AccountViewHolder
viewHolder.text_account_title.text = accountVO.title
viewHolder.text_account_bank.text = accountVO.bank
viewHolder.text_account_account.text = accountVO.account
viewHolder.text_account_name.text = accountVO.name
viewHolder.text_account.setOnClickListener() {
// log
// Toast.makeText(context, "${accountVO.title}, ${accountVO.content}", Toast.LENGTH_SHORT).show()
val accountFragment = AccountFragment()
val bundle = Bundle()
bundle.putString("title", accountVO.title)
bundle.putString("content", accountVO.content)
accountFragment.arguments = bundle
AccountDetailDialogFragment().show(activity?.supportFragmentManager as FragmentManager, "dialog_event")
}
}
AccountDetailDialogFragment
class AccountDetailDialogFragment : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.activity_account_detail_dialog_fragment, container, false)
view.text_account_detail_title.text = arguments?.getString("title")
view.text_account_detail_content.text = arguments?.getString("content")
isCancelable = false
return view
}
}

You didn't actually set the arguments on your AccountDetailDialogFragment, you set it on your accountFragment (which you didn't even use):
val bundle = Bundle()
bundle.putString("title", accountVO.title)
bundle.putString("content", accountVO.content)
val dialogFragment = AccountDetailDialogFragment()
dialogFragment.arguments = bundle
dialogFragment.show(requireActivity().supportFragmentManager, "dialog_event")
Note that you should make sure your AccountDetailDialogFragment uses the right import for its superclass (you shouldn't need to cast the supportFragmentManager).

try to get this inot onviewCreated
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.text_account_detail_title.text = arguments?.getString("title")
view.text_account_detail_content.text = arguments?.getString("content")
}
Or if its not working than you can try using instance it's a good way to transfer data

change this
AccountDetailDialogFragment().show(activity?.supportFragmentManager as FragmentManager, "dialog_event")
to
accountFragment.show(activity?.supportFragmentManager as FragmentManager, "dialog_event")
this will work :)

Related

I can't get data in fragment By Using Bundle()

in recycler view when click item work and clicked and the fragment open successfully but the date can't send or error is show in fragment when call the date in Bundle()
//This Code In RecyclerView
holder.setItemClickListener(object:IItemClickListenerQuran{
override fun clickedItem(view: View, position: Int) {
Toast.makeText(activity, "Click At Quran Sora: " + items[position].name,Toast.LENGTH_SHORT).show()
val bundle = Bundle()
bundle.putString("SoraName", items[position].name)
val fragment = SoraDetailsFragment()
val activity = view.context as AppCompatActivity
activity.supportFragmentManager.beginTransaction().replace(R.id.main_Fragment_Continer, fragment).addToBackStack(null).commit()
//This Code In Fragment
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view:View = inflater.inflate(R.layout.fragment_sora_details, container, false)
val args = arguments
val SoraName = args!!.getString("SoraName")
Log.d("receiver", "SoraName: " + SoraName);
return view
You are creating bundle . But you didn't bind the bundle as arguments.
Try adding this line.
val bundle = Bundle()
bundle.putString("SoraName", items[position].name)
val fragment = SoraDetailsFragment()
fragment.arguments = bundle // This is where bundle is attached to fragment as arguments
if you want to pass the data using safeArg, here is the approach
enter link description here
You can use this
val bundle = Bundle()
bundle.putBoolean("SoraName", items[position].name)
val fragment = SoraDetailsFragment()
fragment.setArguments(bundle)
val activity = view.context as AppCompatActivity
activity.supportFragmentManager.beginTransaction().replace(R.id.main_Fragment_Continer, fragment).addToBackStack(null).commit()

Getting NullPointerException when trying to display the data of passed object from one fragment to another

Here is my code on the sender fragment
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_list_card,container,false)
rcvAdapter = CardAdapter(cardList,this)
view.cardRecyclerView.layoutManager = LinearLayoutManager(container?.context,LinearLayoutManager.VERTICAL,false)
view.cardRecyclerView.adapter = rcvAdapter
return view
}
override fun onClick(card: Card) {
val cardBundle = Bundle()
cardBundle.putSerializable("Card",card)
val infoFrag = CardInfoFrag()
infoFrag.arguments = cardBundle
val transaction = activity?.supportFragmentManager?.beginTransaction()
transaction?.replace(R.id.fragmentContainer,infoFrag)
transaction?.commit()
}
Here is the code on the receiver
class CardInfoFrag : Fragment() {
private val card : Card? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle = Bundle(arguments)
val card : Card = bundle.getSerializable("Card") as Card
Log.d("CARDINFO: ",card.name+" "+ card.cardDate+" "+card.cardNum)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
cardNameInfo.text = card?.name
cardExDateInfo.text = card?.cardDate
cardNumInfo.text = card?.cardNum
return inflater.inflate(R.layout.fragment_card_info,container,false)
}
}
The cardList is declared as ArrayList<Card>
The Card object
class Card (val cardNum : String, val cardDate : String, val name : String) :Serializable{
}
The logcat, when I attempt to create a new fragment with data from the passed object, says my cardNameInfo.text can't be null while the log command clearly says I received the object and its data. I can't work out what may cause the problem
Any tip is appreciated
As its name implies, onCreateView get called before the fragment view is created; So within the onCreateView, you need to explicitly use the view that will be returned by it to access any underlying views.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_card_info,container,false)
cardNameInfo = view.findViewById<TextView>(R.id.foo1)
cardExDateInfo= view.findViewById<TextView>(R.id.foo2)
cardNumInfo= view.findViewById<TextView>(R.id.foo3)
cardNameInfo.text = card?.name
cardExDateInfo.text = card?.cardDate
cardNumInfo.text = card?.cardNum
return view
}
Change the foo Ids to the corresponding ids in the fragment layout
Try this once, when you are getting the Bundle, the arguments is already a Bundle object. Maybe if you do something like this it might work: ( My answer is based off this answer :) )
class CardInfoFrag : Fragment() {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle: Bundle? = arguments
bundle?.let{
val card : Card = it.getSerializable("Card") as Card
Log.d("CARDINFO: ",card.name+" "+ card.cardDate+" "+card.cardNum)
}
}
...
}

Data is not transferred from activity to fragment

I'm trying to write a data transfer from an activity to a fragment, but I'm catching "NullPointerException"
Code MainActivity:
val btn1 = findViewById<Button>(R.id.button)
btn1.setOnClickListener {
BlankFragment2.getNewInstance(321)
val fm = supportFragmentManager
val ft = fm.beginTransaction()
ft.replace(R.id.fragment, BlankFragment2())
ft.commit()
}
Code Fragment:
class BlankFragment2 : Fragment() {
var str: Int = 0
companion object {
fun getNewInstance(args: Int): BlankFragment2 {
val fragment = BlankFragment2()
fragment.arguments?.putInt("one", args)
return fragment
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
str = arguments!!.getInt("one")
return inflater.inflate(R.layout.fragment_blank2, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val txt = view.findViewById<TextView>(R.id.textTest)
txt.text = str.toString()
}
}
I know about protection against null-values, and the problem is that I am sure that the value is passed and null cannot be there
instead of
ft.replace(R.id.fragment, BlankFragment2()
you should use
ft.replace(R.id.fragment, BlankFragment2.getNewInstance(321).
Because your BlankFragment2.getNewInstance(321) statement above is kind of useless to the fragmentManager. FragmentManager is creating fragment using BlankFragment2() as you provided the Fragment in the replace call.
And that is the reason for nullpointerexception because in reality, your Fragment didn't get any int value at all as the Fragment instance used was created with the empty constructor.
And also update your companion object code like below.
companion object {
fun getNewInstance(args: Int): BlankFragment2 {
val fragment = BlankFragment2()
val args = Bundle()
args.putInt("one", args)
fragment.setArguments(args)
return fragment
}
}
because right now your code is actually not setting argument but try to access argument and setting value to it.

How to communicate from Fragment to ViewModel?

I currently have an interface that's implemented in the MainActivity that allows communication with the NumberFragment. The onCountClicked is the method in NumberFragment receiving the id of the item click.
Question
How can I send the onCountClicked position to the NumberFragmentViewModel every time an item is clicked?
Note: Using databinding & recycleview
Main Activity
val newFragment = NumberFragment()
val args = Bundle()
args.putInt(NumberFragment().onCountClicked(data).toString(),data.toInt())
newFragment.arguments = args
Number Fragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val sleepTrackerViewModel =
ViewModelProviders.of(
this, viewModelFactory).get(NumberViewModel::class.java)
setHasOptionsMenu(true)
binding.setLifecycleOwner(this)
binding.sleepTrackerViewModel = sleepTrackerViewModel
//Observes for any changes on database and updates the UI
sleepTrackerViewModel.dbCount.observe(this, Observer {dbCount ->
dbView.text = dbCount.number.toString()
})
return binding.root
}
fun onCountClicked(position: Long) {
Log.i("NumberF" , "------------->" + position)
}
You can just simply create a method in the viewModel that receives that position and updates the value of the live data. I would do it like this:
private val _idItemClicked = MutableLiveData<Int>()
val idItemClicked: LiveData<Int> = _idItemClicked
fun setIdItemClicked(id: Int) {
_idItemClicked.value = id
}
Now you call the function setIdItemClicked to set a new value.

Pass data between fragments in kotlin android studio

I want to pass some data from PowerofMind to wishlist fragment but I encountered with some error.
This Activity from where data has to be transferred
wish?.setOnClickListener({
val name = "Power of Subconcoius Mind"
val intent = Intent(this#PowerofMind, WishlistFragment::class.java)
intent.putExtra("Book: ", name)
startActivity(intent)
Toast.makeText(this, "Added to WishList", Toast.LENGTH_SHORT).show()
})
I want to show data in this activity as
class WishlistFragment : Fragment() {
var result: TextView? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_wishlist, null)
result =view.findViewById(R.id.list1)
val name = activity?.intent?.getStringExtra("Book: ")
list1.text = "Book: $name"
return view
}
}
But there is an error on Intent. Please Help
Here is an example how to instantiate a fragment with factory method:
companion object {
private const val MY_DATA_KEY = "my_data"
private const val ANOTHER_DATA_KEY = "another_data"
fun newInstance(mySerializableData: Any, anotherData: Int) = MyFragment().apply {
//bundleOf() is an exstension method from KTX https://developer.android.com/kotlin/ktx
arguments = bundleOf(MY_DATA_KEY to mySerializableData, ANOTHER_DATA_KEY to anotherData)
}
}
Here is how you can pass data between fragment in kotlin using Parcelable class:
on Button Click:
override fun onClick(v: View?) {
firstName = editTextName!!.text.toString()
lastName = editTextLast!!.text.toString()
Toast.makeText(context, firstName, Toast.LENGTH_SHORT).show()
// val viewFragment = ViewFragment()
// val transaction = fragmentManager.beginTransaction()
// transaction.replace(R.id.fragmentContainer, viewFragment)
// transaction.commit()
var details = Details(firstName!!, lastName!!)
val viewFragment = ViewFragment()
val bundle = Bundle()
bundle.putParcelable(KEY_PARSE_DATA, details)
viewFragment.setArguments(bundle)
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.fragmentContainer, viewFragment)
transaction.commit()
}
Here is an parcel class how to handle data
#Parcelize
class Details(val firstName: String, val lastName: String) : Parcelable
on another fragment
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_view, container, false)
textViewName = view.findViewById(R.id.text_name_another) as TextView
textViewLastName = view.findViewById(R.id.text_surname_another) as TextView
val bundle = arguments
if (bundle != null) {
val details = bundle.getParcelable<Details>(KEY_PARSE_DATA)
textViewName!!.setText(details.firstName)
textViewLastName!!.setText(details.lastName)
}
return view
}
Currently I don't know if this required or not in kotlin in app gradle (Check this before used)
androidExtensions {
experimental = true
}
In your WishlistFragment you are creating a new Intent instead of getting the one provided by the activity.
As you are using Kotlin, you can directly use intent instead of getIntent().
You could use also the synthetic advantage of kotlin, and drop that findViewById.
And as a tip, do not use string concatenation ;)
Your fragment would look something like the following:
class WishlistFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_wishlist, null)
val name = activity?.intent?.getStringExtra("Book: ")
many.text = "Book: $name"
}

Categories

Resources