Kotlin interface, sending data between two fragments - android

I am looking to send a string from FragmentA to FragmentDialog by means of an interface Communicator through my Main Activity (which automatically opens FragmentDialog). Some code to illustrate what I have:
class FragmentA: Fragment() {
private lateinit var communicator: Communicator
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_A, container, false)
val title = "My Title"
button.setOnClickListener { communicator.passData(title) }
return view
}
}
class FragmentDialog : DialogFragment() {
var title: String? = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.dialog, container, false)
view.button_close.setOnClickListener { dismiss() }
title = arguments?.getString("title")
view.dialog_title.text = title
return view
}
}
interface Communicator {
fun passData (titleInput: String)
}
and in my Main Activity, which extends the interface:
private val fragmentDialog = FragmentDialog()
override fun passData(titleInput: String) {
val bundle = Bundle()
bundle.putString("title", titleInput)
fullScreenDialog.arguments = bundle
val transaction = supportFragmentManager.beginTransaction().add(android.R.id.content, fragmentDialog).addToBackStack(null).commit()
}
When I click the button in FragmentA, I want to send the string title to Communicator, set the XML element with id dialog_title in FragmentDialog and automatically open the fragment. In fact, this works fine. The issue is that my "back button" in FragmentDialog, i.e. view.button_close.setOnClickListener { dismiss() } only works exactly once. If I click button in FragmentA again, FragmentDialog opens fine with the correct title still but button_close no longer dismisses the dialog. What could be causing this? I am not getting any consol errors.

Related

Passing data from fragment to mainactivity with tablayout and adapater. Kotlin android app

i need help with the following situation.
I hava a fragment, adapter and mainactivity. i use fragment and adapter for tablayout.
Im trying to pass data from edittext in fragment to activity.
When i am using Intent to pass data from fragment to mainactivit , it crashes the app.
Is there a another posibility to pass data like via adapter to mainactivity?
class person : Fragment() {
lateinit var Sname : EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_person, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Sname= view.findViewById(R.id.snamedittext)
senddata()
}
private fun senddata() {
var name = Sname.toString()
val intent = Intent(activity,personactivity::class.java)
intent.putExtra("name", name)
startActivity(intent)
}
}

Error during passing data between fragment

Im trying to pass data between two fragments but i have an error with arguments in execution when i launch fullFragment
i updated my code
Can you help me ?
architecture :
ListeFragment (sender) :
class ListeFragment : Fragment() {
companion object {
fun newInstance(s: String) = ListeFragment()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val layout = inflater.inflate(R.layout.liste_fragment, container, false)
val photo1 = layout.findViewById<ImageView>(R.id.imageButton1)
val model = ViewModelProviders.of(this).get(ListeViewModel::class.java)
imageButton1.setOnClickListener {
val newFragment = FullFragment()
val args = Bundle()
args.putString("key1", "data")
newFragment.arguments = args
Navigation.findNavController(imageButton1).navigate(R.id.versFullFragment);
}
FullFragment (receiver):
class FullFragment : Fragment() {
companion object {
fun newInstance() = FullFragment()
}
private lateinit var viewModel: FullViewModel
override fun onCreate( savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var value1 = getArguments()?.getString("key1")
Log.v("value" , value1.toString())
Toast.makeText(context, value1.toString(), Toast.LENGTH_SHORT).show()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val layout = inflater.inflate(R.layout.full_fragment, container, false)
return layout
}
I don't know what "newFragment.arguments = args" do because in FullFragment class I don't see any variable with that name, however you have to use "Fragment.setArguments(Bundle)" to set Fragment Arguments from the first one. Then in the Full you will have a correct result from "FullFragment.getArguments()" method.
PS: don't forget that the Context could be NULL in Fragment class and it should be handled in proper way.

Numberpicker send data to HomeFragment (Fragment to Fragment)

I have app who have viewpagers and in inside is numberpicker. I try to send this data to my HomeFragment but crash my app. This is my source code. What i do wrong?
Create Interface for communication
interface Communicator {
fun passData(numberpicker: NumberPicker) {
}
This is my fragment with numberpicker
lateinit var comm: Communicator
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_period_length, container, false)
view.number_picker_period?.minValue = 21
view.number_picker_period?.maxValue = 35
view.number_picker_period?.wrapSelectorWheel = true
val viewPager = activity?.findViewById<ViewPager2>(R.id.viewPager)
view.next_txt_period.setOnClickListener {
viewPager?.currentItem = 1
comm.passData(view.number_picker_period)
}
return view
}
This is MainActivity
val fragment1 = DaysLength()
supportFragmentManager.beginTransaction().replace(R.id.content_id, fragment1).commit()
}
override fun passData(numberpicker: NumberPicker) {
val bundle = Bundle()
bundle.putString("input_txt", number_picker_period.toString())
val transaction = this.supportFragmentManager.beginTransaction()
val fragment2 = HomeFragment()
fragment2.arguments = bundle
}
My HomeFragment
var inputtext: String? = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
inputtext = arguments?.getString("input_txt")
view.output_numberpicker.text = inputtext
return view
What i do wrong?
Error
Unable to start activity ComponentInfo{com.example.oapp/com.example.oapp.MainActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f080067 (com.example.oapp:id/content_id) for fragment DaysLength{aa77410}
your main activity is crashing on this line as it doesn't know what the view "number_picker_period" is
bundle.putString("input_txt", number_picker_period.toString())
try accessing the number picker through the parameter in the function called "numberPicker", Or alternatively, change your passData interface function to return the string value instead of the entire numberPicker

Android Navigation Component saveState and restoreState

Guys I need your help.
I use android navigation component and want to save backstack after user press button and restore it after. I found 2 methods
navController.saveState(): Bundle and navController.restoreState(bundle: Bundle).
But i have problem in use it. Seems like saveState work greate (i see bundle, and backstack inside), but i dont understand how to use restoreState, because the documentation says:
Restores all navigation controller state from a bundle. This should be called before any call to setGraph.
https://developer.android.com/reference/kotlin/androidx/navigation/NavController#restorestate
Okay, i did it, seems like backstack restored, but on screen i see first fragment (instead of the one I had when I saved it). What i do wrong?
Code:
FirstFragment
private val TAG = this::class.java.name
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_forward.setOnClickListener { findNavController().navigate(R.id.action_firstFragment_to_secondFragment) }
btn_back.setOnClickListener { requireActivity().onBackPressed() }
}
}
SecondFragment
class SecondFragment : Fragment() {
private val TAG = this::class.java.name
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_forward.setOnClickListener { findNavController().navigate(R.id.action_secondFragment_to_thirdFragment) }
btn_back.setOnClickListener { requireActivity().onBackPressed() }
}
}
ThirdFragment
class ThirdFragment : Fragment() {
private val TAG = this::class.java.name
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_third, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_finish.setOnClickListener {
(requireActivity() as MainActivity).saveState() //here save bundle
requireActivity().finishAfterTransition()
}
btn_back.setOnClickListener { requireActivity().onBackPressed() }
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private val TAG = "MySuperActivity"
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "onCreate($savedInstanceState) called")
initNavController()
}
private fun initNavController() {
val navHostFragment = nav_host_fragment as NavHostFragment
val graphInflater = navHostFragment.navController.navInflater
val graph = graphInflater.inflate(R.navigation.main_graph)
navController = navHostFragment.navController
navHostFragment.childFragmentManager
if (App.instance.savedBundle != null) {
Log.d(TAG, "bundle: ${App.instance.savedBundle}")
navController.restoreState(App.instance.savedBundle)
graph.startDestination = R.id.thirdFragment
}
navController.graph = graph
Log.d(TAG, "navController.currentDestination: ${navController.currentDestination}")
Log.d(TAG, "navController.graph.startDestination: ${navController.graph.startDestination}")
}
fun saveState(){
App.instance.savedBundle = navController.saveState()
Log.d(TAG, "saveState() : ${App.instance.savedBundle}")
}
}
here some logs: logs
full code:github
I am not sure if my answer helps you, but I had many issues trying to save the navigation state from handling rotations. The issue that I had comes from an old version of the navigation component, I update to the most recent, and it fixes the issue:
def android_navigation = '2.3.4'
implementation "android.arch.navigation:navigation-fragment-ktx:$android_navigation"
implementation "android.arch.navigation:navigation-ui-ktx:$android_navigation"
implementation "androidx.navigation:navigation-dynamic-features-fragment:$android_navigation"

How do I correctly use Kotlin to call a blank fragment from the Home fragment?

class HomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val v = inflater.inflate(R.layout.fragment_home, container, false)
val fab = v.findViewById(R.id.fab) as FloatingActionButton
fab.setOnClickListener {
val blankFragment = BlankFragment()
val manager = childFragmentManager
manager.beginTransaction().replace(R.id.frame_container, blankFragment, blankFragment.tag).commit()
// System.out.println("You have reached the floating action button")
}
return v
}
}
Getting a no view found error. I may have issues with the R.id.frame_content but Kotlin doesn't immediately identify all id values...
This may not be the best way and I apologize for the horrible formatting I does this while answer out on my phone and it's hard to get it perfect. Anyways In the activity that holds your fragments, such as MainActivity.kt add...
supportFragmentManager.beginTransaction.add(R.id.fragment_home, HomeFragment.newInstance, "HomeFragment").commit()
In your HomeFragment.kt change the following.
class HomeFragment: Fragment(){
companion object {
fun newInstance(): HomeFragment{
return HomeFragment() }
fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_home, container, false)
val activity = activity
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val clickListener = View.OnClickListener { view ->
when (view.getId()) {
R.id.fab -> NextFragment()
}
}
fab.setOnClickListener(clickListener)
}
NextFragment(){
val fragManager = activity?.supportFragmentManager
fragManager?.beginTransaction()?.replace(R.id.frame_container, BlankFragment.newInstance(), "blankFragment")?.commit()
}
Make sure you make the same changes to BlankFragment.kt
class BlankFragment: Fragment(){
companion object {
fun newInstance(): BlankFragment{
return BlankFragment() }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_blank, container, false)
val activity = activity
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Do some stuff with your views in BlankFragment here
}
}

Categories

Resources