Get value from Bottom Sheet Dialog Fragment
Asked Answered
M

8

20

I'm starting bottomSheetDialogFragment from a fragment A. I want to select the date from that bottomSheetDialogFragment then set it in the fragment A.

The select date is already done, I just want to get it in the fragment A to set it in some fields.

How can I get the value? Any suggestions how to do it?

Metalware answered 12/4, 2018 at 10:56 Comment(3)
Share your codePare
Create one interface. Implement that interface in Fragment A then pass the reference of that interface in BottomSheetDialog, when you are changing the date, in that method call that interface method and pass your date in method parameter. Now you have your date in Fragment A use it.Bundestag
Can you write an example?Metalware
P
24

Create an interface class like this

public interface CustomInterface {

    public void callbackMethod(String date);
}

Implement this interface in your Activity or Fragment. and make an object of this Interface.

private CustomInterface callback;

Initialize it in onCreate or onCreateView

callback=this;

Now pass this callback in your BottomSheetDialogFragment constructor when you call it.

yourBottomSheetObject = new YourBottomSheet(callback);
yourBottomSheetObject.show(getSupportFragmentManager()," string");

Now in your BottomSheetFragment's constructor

private CustomInterface callback;

public SelectStartTimeSheet(CustomInterface callback){

this.callback=callback;

}

And at last use this callback object to set your date

callback.callbackMethod("your date");

and yout will recieve this date in your Fragment or Your Activity in callbackMethod function.

Pettifogger answered 12/4, 2018 at 12:27 Comment(4)
this is not working for me. when i create a constructor with argument in bottomsheetfragment, it throws a warning saying that "Avoid non-default constructors in fragments"... any workaround? thanksSoftcover
Just put this line @SuppressLint("ValidFragment") over your class namePettifogger
Don't suppress, you can do: fragment.setCallbackListener(listener). But this is still not the preferred way if you are calling from a fragment or an activity. you can use getTargetFragment() for example in the case of fragmentRifling
@AndreaAranguren has given the better solution using getTargetFragment. This should be the chosen answerNonconformity
D
10

override the constructor of a fragment is a bad practice as the document said:

Every fragment must have an * empty constructor, so it can be instantiated when restoring its * activity's state.

if you using another constructor that passing a callback as the param, when the fragment is resotored by the framework, your app crash

the recommend way is using viewModel and livedata.

Dialectician answered 29/5, 2019 at 2:32 Comment(0)
U
9

Android navigation architecture component

eg:

Suppose you open Fragment B from Fragment A using navController.

and you want some data from fragment B to Fragment A.

class B :BottomSheetDialogFragment() {

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

        root.sampleButton.setOnClickListener {
            val navController = findNavController()
            navController.previousBackStackEntry?.savedStateHandle?.set("your_key", "your_value")
            dismiss()

        }
}

and in your Fragment A:

findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("your_key")
                ?.observe(viewLifecycleOwner) {
    
                    if (it == "your_value") {
                        //your code
    
                    }
    
                }
Ungava answered 10/3, 2021 at 18:14 Comment(0)
L
3

you can use do as below:

Select Account Fragment code


class SelectAccountFragment(val clickListener: OnOptionCLickListener) : BottomSheetDialogFragment() {


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.bottom_fragment_accounts, container, false)
    }



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

        val list = DataProcessorApp(context).allUsers

        val rvAccounts = view.findViewById<RecyclerView>(R.id.rvAccounts)

        rvAccounts.layoutManager = LinearLayoutManager(context)
        rvAccounts.adapter = AccountsAdapter(context, list)

        Log.e(tag,"Accounts "+list.size);

        tvAccountAdd.setOnClickListener {
            val intent = Intent(context,LoginActivity::class.java)
            startActivity(intent)
        }

        tvManageAccounts.setOnClickListener {
            Log.e(tag,"Manage Click")
            clickListener.onManageClick()
        }
    }


    interface OnOptionCLickListener{
        fun onManageClick()
    }

}


Now show and get call back into another fragment /activity as below

 SelectAccountFragment accountFragment = new SelectAccountFragment(() -> {

          //get fragment by tag and dismiss it

          BottomSheetDialogFragment fragment = (BottomSheetDialogFragment) getChildFragmentManager().findFragmentByTag(SelectAccountFragment.class.getSimpleName();
          if (fragment!=null){
               fragment.dismiss();
          }

});

accountFragment.show(getChildFragmentManager(),SelectAccountFragment.class.getSimpleName());
Legitimize answered 9/7, 2019 at 10:17 Comment(0)
P
2

If you are using BottomSheetDialogFragment , since it's a fragment, you should create your interface and bind to it at onAttach lifecycle method of the fragment , doing the appropriate cast of activity reference to your listener/callback type.

Implement this interface in your activity and dispatch change when someone click in a item of fragment's inner recyclerview, for instance

It's a well known pattern and are explained better at here

One big advice is rethink your app architecture, since the best approach is to always pass primitive/simple/tiny data between Android components through Bundle, and your components are able to retrieve the required state with their dependencies later on.

For example, you should never pass along large Objects like Bitmaps, Data Classes , DTO's or View References.

  • first there is some serialization process going on regarding Parcel which impacts in app responsiveness
  • second it can lead you to TransactionTooLarge type of error.

Hope that helps!

Pogonia answered 2/10, 2019 at 20:12 Comment(0)
K
0

You can also use LocalBroadcastManager. And as hglf said, it is better to keep the empty constructor for your fragment and use newInstance(Type value) instead to instantiate your fragment if you still want to use the interface callBack way.

Kenya answered 1/6, 2019 at 2:2 Comment(0)
N
0

You can use the benefit of Navigation library:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val navController = findNavController();
    // After a configuration change or process death, the currentBackStackEntry
    // points to the dialog destination, so you must use getBackStackEntry()
    // with the specific ID of your destination to ensure we always
    // get the right NavBackStackEntry
    val navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment)

    // Create our observer and add it to the NavBackStackEntry's lifecycle
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains("key")) {
            val result = navBackStackEntry.savedStateHandle.get<String>("key");
            // Do something with the result
        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })
}

For more info, read the document.

Necessaries answered 15/2, 2021 at 10:37 Comment(0)
T
-5

The accepted answer is wrong.

What you can do is just user Fragment A's childFragmentManager when calling show().

like this:

val childFragmentManager = fragmentA.childFragmentManager
bottomSheetDialogFragment.show(childFragmentManager, "dialog") 
Tuque answered 1/10, 2020 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.