Callback to a Fragment from a DialogFragment

AndroidAndroid FragmentsCallbackAndroid Dialogfragment

Android Problem Overview


Question: How does one create a callback from a DialogFragment to another Fragment. In my case, the Activity involved should be completely unaware of the DialogFragment.

Consider I have

public class MyFragment extends Fragment implements OnClickListener

Then at some point I could do

DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
dialogFrag.show(getFragmentManager, null);

Where MyDialogFragment looks like

protected OnClickListener listener;
public static DialogFragment newInstance(OnClickListener listener) {
    DialogFragment fragment = new DialogFragment();
    fragment.listener = listener;
    return fragment;
}

But there is no guarantee that the listener will be around if the DialogFragment pauses and resumes through its lifecycle. The only guarantees in a Fragment are those passed in through a Bundle via setArguments and getArguments.

There is a way to reference the activity if it should be the listener:

public Dialog onCreateDialog(Bundle bundle) {
    OnClickListener listener = (OnClickListener) getActivity();
    ....
    return new AlertDialog.Builder(getActivity())
        ........
        .setAdapter(adapter, listener)
        .create();
}

But I don't want the Activity to listen for events, I need a Fragment. Really, it could be any Java object that implements OnClickListener.

Consider the concrete example of a Fragment that presents an AlertDialog via DialogFragment. It has Yes/No buttons. How can I send these button presses back to the Fragment that created it?

Android Solutions


Solution 1 - Android

Activity involved is completely unaware of the DialogFragment.

Fragment class:

public class MyFragment extends Fragment {
int mStackLevel = 0;
public static final int DIALOG_FRAGMENT = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        mStackLevel = savedInstanceState.getInt("level");
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("level", mStackLevel);
}

void showDialog(int type) {

    mStackLevel++;

    FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
    Fragment prev = getActivity().getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    switch (type) {

        case DIALOG_FRAGMENT:

            DialogFragment dialogFrag = MyDialogFragment.newInstance(123);
            dialogFrag.setTargetFragment(this, DIALOG_FRAGMENT);
            dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");

            break;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch(requestCode) {
            case DIALOG_FRAGMENT:

                if (resultCode == Activity.RESULT_OK) {
                    // After Ok code.
                } else if (resultCode == Activity.RESULT_CANCELED){
                    // After Cancel code.
                }

                break;
        }
    }
}

}

DialogFragment class:

public class MyDialogFragment extends DialogFragment {

public static MyDialogFragment newInstance(int num){

    MyDialogFragment dialogFragment = new MyDialogFragment();
    Bundle bundle = new Bundle();
    bundle.putInt("num", num);
    dialogFragment.setArguments(bundle);

    return dialogFragment;

}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

    return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.ERROR)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setPositiveButton(R.string.ok_button,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent());
                        }
                    }
            )
            .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent());
                }
            })
            .create();
}
}

Solution 2 - Android

TargetFragment solution doesn't seem the best option for dialog fragments because it may create IllegalStateException after application get destroyed and recreated. In this case FragmentManager couldn't find the target fragment and you will get an IllegalStateException with a message like this:

>"Fragment no longer exists for key android:target_state: index 1"

It seems like Fragment#setTargetFragment() is not meant for communication between a child and parent Fragment, but rather for communication between sibling-Fragments.

So alternative way is to create dialog fragments like this by using the ChildFragmentManager of the parent fragment, rather then using the activities FragmentManager:

dialogFragment.show(ParentFragment.this.getChildFragmentManager(), "dialog_fragment");

And by using an Interface, in onCreate method of the DialogFragment you can get the parent fragment:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        callback = (Callback) getParentFragment();
    } catch (ClassCastException e) {
        throw new ClassCastException("Calling fragment must implement Callback interface");
    }
}

Only thing left is to call your callback method after these steps.

For more information about the issue, you can check out the link: https://code.google.com/p/android/issues/detail?id=54520

Solution 3 - Android

I followed this simple steps to do this stuff.

  1. Create interface like DialogFragmentCallbackInterface with some method like callBackMethod(Object data). Which you would calling to pass data.

  2. Now you can implement DialogFragmentCallbackInterface interface in your fragment like MyFragment implements DialogFragmentCallbackInterface

  3. At time of DialogFragment creation set your invoking fragment MyFragment as target fragment who created DialogFragment use myDialogFragment.setTargetFragment(this, 0) check setTargetFragment (Fragment fragment, int requestCode)

    MyDialogFragment dialogFrag = new MyDialogFragment();
    dialogFrag.setTargetFragment(this, 1); 
    
  4. Get your target fragment object into your DialogFragment by calling getTargetFragment() and cast it to DialogFragmentCallbackInterface.Now you can use this interface to send data to your fragment.

    DialogFragmentCallbackInterface callback = 
               (DialogFragmentCallbackInterface) getTargetFragment();
    callback.callBackMethod(Object data);
    

That's it all done! just make sure you have implemented this interface in your fragment.

Solution 4 - Android

Maybe a bit late, but may help other people with the same question like I did.

You can use setTargetFragment on Dialog before showing, and in dialog you can call getTargetFragment to get the reference.

Solution 5 - Android

The Communicating with Other Fragments guide says the Fragments should communicate through the associated Activity.

> Often you will want one Fragment to communicate with another, for > example to change the content based on a user event. All > Fragment-to-Fragment communication is done through the associated > Activity. Two Fragments should never communicate directly.

Solution 6 - Android

You should define an interface in your fragment class and implement that interface in its parent activity. The details are outlined here http://developer.android.com/guide/components/fragments.html#EventCallbacks . The code would look similar to:

Fragment:

public static class FragmentA extends DialogFragment {

    OnArticleSelectedListener mListener;

    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
}

Activity:

public class MyActivity extends Activity implements OnArticleSelectedListener{

    ...
    @Override
    public void onArticleSelected(Uri articleUri){

    }
    ...
}

Solution 7 - Android

A recommended approach is to use the new Fragment Result API.

By using it, you do not need to override onAttach(context) nor setTargetFragment(), which is now deprecated.


1 - Add a result listener on parent Fragment's onCreate:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    childFragmentManager.setFragmentResultListener("requestKey", this) { key, bundle ->
        val result = bundle.getString("bundleKey")
    }

}

2- On child Fragment, set the result (on a button click listener, for instance):

button.setOnClickListener {
    val result = "resultSample"

    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}

More info on the docs: https://developer.android.com/guide/fragments/communicate#fragment-result

Hope it helps!

Solution 8 - Android

According to the official documentation:

Fragment#setTargetFragment > Optional target for this fragment. This may be used, for example, if this fragment is being started by another, and when done wants to give a result back to the first. The target set here is retained across instances via FragmentManager#putFragment.

Fragment#getTargetFragment > Return the target fragment set by setTargetFragment(Fragment, int).

So you can do this:

// In your fragment

public class MyFragment extends Fragment implements OnClickListener {
    private void showDialog() {
        DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
        // Add this
        dialogFrag.setTargetFragment(this, 0);
        dialogFrag.show(getFragmentManager, null);
    }
    ...
}

// then

public class MyialogFragment extends DialogFragment {
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Then get it
        Fragment fragment = getTargetFragment();
		if (fragment instanceof OnClickListener) {
			listener = (OnClickListener) fragment;
		} else {
			throw new RuntimeException("you must implement OnClickListener");
		}
    }
    ...
}

Solution 9 - Android

The correct way of setting a listener to a fragment is by setting it when it is attached. The problem I had was that onAttachFragment() was never called. After some investigation I realised that I had been using getFragmentManager instead of getChildFragmentManager

Here is how I do it:

MyDialogFragment dialogFragment = MyDialogFragment.newInstance("title", "body");
dialogFragment.show(getChildFragmentManager(), "SOME_DIALOG");

Attach it in onAttachFragment:

@Override
public void onAttachFragment(Fragment childFragment) {
    super.onAttachFragment(childFragment);

    if (childFragment instanceof MyDialogFragment) {
        MyDialogFragment dialog = (MyDialogFragment) childFragment;
        dialog.setListener(new MyDialogFragment.Listener() {
            @Override
            public void buttonClicked() {

            }
        });
    }
}

Solution 10 - Android

Update: Please note that there are easier ways of doing this using view models which I can share if someone is interested.

Kotlin guys here we go!

So the problem we have is that we created an activity, MainActivity, on that activity we created a fragment, FragmentA and now we want to create a dialog fragment on top of FragmentA call it FragmentB. How do we get the results from FragmentB back to FragmentA without going through MainActivity?

Note:

  1. FragmentA is a child fragment of MainActivity. To manage fragments created in FragmentA we will use childFragmentManager which does that!
  2. FragmentA is a parent fragment of FragmentB, to access FragmentA from inside FragmentB we will use parenFragment.

Having said that, inside FragmentA,

class FragmentA : Fragment(), UpdateNameListener {
    override fun onSave(name: String) {
        toast("Running save with $name")
    }

    // call this function somewhere in a clickListener perhaps
    private fun startUpdateNameDialog() {
        FragmentB().show(childFragmentManager, "started name dialog")
    }
}

Here is the dialog fragment FragmentB.

class FragmentB : DialogFragment() {

    private lateinit var listener: UpdateNameListener

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            listener = parentFragment as UpdateNameListener
        } catch (e: ClassCastException) {
            throw ClassCastException("$context must implement UpdateNameListener")
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            val binding = UpdateNameDialogFragmentBinding.inflate(LayoutInflater.from(context))
            binding.btnSave.setOnClickListener {
                val name = binding.name.text.toString()
                listener.onSave(name)
                dismiss()
            }
            builder.setView(binding.root)
            return builder.create()
        } ?: throw IllegalStateException("Activity can not be null")
    }
}

Here is the interface linking the two.

interface UpdateNameListener {
    fun onSave(name: String)
}

That's it.

Solution 11 - Android

I was facing a similar problem. The solution that I found out was :

  1. Declare an interface in your DialogFragment just like James McCracken has explained above.

  2. Implement the interface in your activity (not fragment! That is not a good practice).

  3. From the callback method in your activity, call a required public function in your fragment which does the job that you want to do.

Thus, it becomes a two-step process : DialogFragment -> Activity and then Activity -> Fragment

Solution 12 - Android

I am getting result to Fragment DashboardLiveWall(calling fragment) from Fragment LiveWallFilterFragment(receiving fragment) Like this...

 LiveWallFilterFragment filterFragment = LiveWallFilterFragment.newInstance(DashboardLiveWall.this ,"");

 getActivity().getSupportFragmentManager().beginTransaction(). 
 add(R.id.frame_container, filterFragment).addToBackStack("").commit();

where

public static LiveWallFilterFragment newInstance(Fragment targetFragment,String anyDummyData) {
        LiveWallFilterFragment fragment = new LiveWallFilterFragment();
        Bundle args = new Bundle();
        args.putString("dummyKey",anyDummyData);
        fragment.setArguments(args);

        if(targetFragment != null)
            fragment.setTargetFragment(targetFragment, KeyConst.LIVE_WALL_FILTER_RESULT);
        return fragment;
    }

setResult back to calling fragment like

private void setResult(boolean flag) {
        if (getTargetFragment() != null) {
            Bundle bundle = new Bundle();
            bundle.putBoolean("isWorkDone", flag);
            Intent mIntent = new Intent();
            mIntent.putExtras(bundle);
            getTargetFragment().onActivityResult(getTargetRequestCode(),
                    Activity.RESULT_OK, mIntent);
        }
    }

onActivityResult

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == KeyConst.LIVE_WALL_FILTER_RESULT) {

                Bundle bundle = data.getExtras();
                if (bundle != null) {

                    boolean isReset = bundle.getBoolean("isWorkDone");
                    if (isReset) {
                        
                    } else {
                    }
                }
            }
        }
    }

Solution 13 - Android

Updated:

I made a library based on my gist code that generates those casting for you by using @CallbackFragment and @Callback.

https://github.com/zeroarst/callbackfragment.

And the example give you the example that send a callback from a fragment to another fragment.

Old answer:

I made a BaseCallbackFragment and annotation @FragmentCallback. It currently extends Fragment, you can change it to DialogFragment and will work. It checks the implementations with the following order: getTargetFragment() > getParentFragment() > context (activity).

Then you just need to extend it and declare your interfaces in your fragment and give it the annotation, and the base fragment will do the rest. The annotation also has a parameter mandatory for you to determine whether you want to force the fragment to implement the callback.

public class EchoFragment extends BaseCallbackFragment {

    private FragmentInteractionListener mListener;

    @FragmentCallback
    public interface FragmentInteractionListener {
        void onEcho(EchoFragment fragment, String echo);
    }
}

https://gist.github.com/zeroarst/3b3f32092d58698a4568cdb0919c9a93

Solution 14 - Android

    this is work for me
    i think you can set callback in display method in your fragment,
    

    **in my fragment**

    val myDialogFragment=MyDialogFragment()
    myDialogFragment.display(fragmentManager!!,this)

//my fragment implement CallbackDialogFragment so set this for display method

    **in dialog fragment**

    lateinit var callBackResult: CallbackDialogFragment


    fun display(fragmentManager: FragmentManager, callback: CallbackDialogFragment) {
        callBackResult = callback
        show(fragmentManager,"dialogTag")
    }

Solution 15 - Android

I solved this in an elegant way with RxAndroid. Receive an observer in the constructor of the DialogFragment and suscribe to observable and push the value when the callback being called. Then, in your Fragment create an inner class of the Observer, create an instance and pass it in the constructor of the DialogFragment. I used WeakReference in the observer to avoid memory leaks. Here is the code:

BaseDialogFragment.java

import java.lang.ref.WeakReference;

import io.reactivex.Observer;

public class BaseDialogFragment<O> extends DialogFragment {

    protected WeakReference<Observer<O>> observerRef;

    protected BaseDialogFragment(Observer<O> observer) {
        this.observerRef = new WeakReference<>(observer);
   }

    protected Observer<O> getObserver() {
    return observerRef.get();
    }
}

DatePickerFragment.java

public class DatePickerFragment extends BaseDialogFragment<Integer>
    implements DatePickerDialog.OnDateSetListener {


public DatePickerFragment(Observer<Integer> observer) {
    super(observer);
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // Use the current date as the default date in the picker
    final Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);

    // Create a new instance of DatePickerDialog and return it
    return new DatePickerDialog(getActivity(), this, year, month, day);
}

@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        if (getObserver() != null) {
            Observable.just(month).subscribe(getObserver());
        }
    }
}

MyFragment.java

//Show the dialog fragment when the button is clicked
@OnClick(R.id.btn_date)
void onDateClick() {
    DialogFragment newFragment = new DatePickerFragment(new OnDateSelectedObserver());
    newFragment.show(getFragmentManager(), "datePicker");
}
 //Observer inner class
 private class OnDateSelectedObserver implements Observer<Integer> {

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Integer integer) {
       //Here you invoke the logic
       
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
}

You can see the source code here: https://github.com/andresuarezz26/carpoolingapp

Solution 16 - Android

More improved way is to just use newInstanceand interface.

Here is a Fragment that needs DailogFragment

public class Fragment extends Fragment implements returnPinInterface {
....
....
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup 
container,Bundle savedInstanceState) {

// A simple call to show DialogFragment

   btnProceed.setOnClickListener(v -> {
        fragment = DailogFragment.newInstance(this);
        fragment.show(getChildFragmentManager(),null );
        fragment.setCancelable(false);
    });


   //Grab whatever user clicked/selected/ or typed
   @Override
   public void onPinReturn(String s) {
      Log.d("ReturnedPin", s);
   }
}

Here comes your DialogFragment

public class PinDialogFragment extends DialogFragment {

 //Create a static variable to help you receive instance of fragment you 
 //passed
public static Fragment fragm;


  // Create new Instance and grab the object passed in Fragment up 
  //there
  public static PinDialogFragment newInstance(Fragment frag) {
    PinDialogFragment fragment = new PinDialogFragment();
    fragm = frag;
    return fragment;
  }

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
   View v = inflater.inflate(R.layout.fragment_pin, container, false);

  //
   btn.setOnClickListener(btn ->                         
   listener.onReturnPin("1234"));
   
   return v;
}


//Use the Fragm to instantiate your Interface

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (fragm instanceof ReturnPinInterface) {
        listener = (ReturnPinInterface) fragm;
    } else {
        throw new RuntimeException("you must implement ReturnPinInterface");
    }
}
}

Enjoy!

Solution 17 - Android

Using onAttach is advised in official Android documentation. So, we can make use of that method.

Make sure that your parent fragment implements a listener e.g. OnPopupButtonClickListener:

public interface OnPopupButtonClickListener {
   void onPositiveButtonClicked();
   void onNegativeButtonClicked();
}

In your parent fragment show your DialogFragment instance using getChildFragmentManager():

PopupDialogFragment dialogFragment = new PopupDialogFragment();
dialogFragment.show(getChildFragmentManager(), "PopupDialogFragment");

In your dialog class which extends DialogFragment instance add this method: (Notice that we are retrieving our parent fragment via getParentFragment() which implements our custom listener interface OnPopupButtonClickListener

@Override
public void onAttach(@NonNull @NotNull Context context) {
   super.onAttach(context);
   // Verify that the host activity implements the callback interface
   try {
      listener = (OnPopupButtonClickListener) getParentFragment();
   } catch (ClassCastException e) {
      // The activity doesn't implement the interface, throw exception
      throw new ClassCastException(getActivity().toString()
                    + " must implement OnPopupButtonClickListener");
   }
}

In your dialog you can then use your listener whenever it is needed in your DialogFragment, for example:

Button positiveButton = view.findViewById(R.id.positiveButton);
positiveButton.setOnClickListener(v -> {
    if (listener != null) {
       listener.onPositiveButtonClicked();
       getDialog().dismiss();
    }
});

Solution 18 - Android

Full example how to use setFragmentResultListener:

Parent fragment MainFragment.kt:

import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener

class MainFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val showDialogButton = view.findViewById<Button>(R.id.dialog_button)
        showDialogButton.setOnClickListener {
            showMyDialog()
        }
    }

    private fun showMyDialog() {
        MyDialogFragment.showOn(this) { bundle ->
            /*here handle bundle result*/
        }
    }
}

your dialog:

import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener

class MyDialogFragment : DialogFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val submitButton = view.findViewById<Button>(R.id.submitButton)
        submitButton.setOnClickListener {
            parentFragment?.setFragmentResult(KEY_CALLBACK_BUNDLE, buildResultBundle())
        }
    }

    private fun buildResultBundle(): Bundle {
        val bundle = Bundle()
        /*here build your result bundle for parent fragment*/
        return bundle
    }

    companion object {

        const val TAG: String = "MyDialogFragment"
        private const val KEY_CALLBACK_BUNDLE: String = "KEY_CALLBACK_BUNDLE"

        fun showOn(fragment: Fragment, callback: (Bundle) -> Unit) {
            val dialog = MyDialogFragment()
            fragment.setFragmentResultListener(KEY_CALLBACK_BUNDLE) { requestKey: String, bundle: Bundle ->
                if (requestKey == KEY_CALLBACK_BUNDLE) {
                    callback(bundle)
                }
            }
            dialog.show(fragment.childFragmentManager, TAG)
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioneternalmattView Question on Stackoverflow
Solution 1 - AndroidPiotr ÅšlesarewView Answer on Stackoverflow
Solution 2 - AndroidOguz OzcanView Answer on Stackoverflow
Solution 3 - AndroidVijay VankhedeView Answer on Stackoverflow
Solution 4 - AndroidRuiView Answer on Stackoverflow
Solution 5 - AndroidEdward BreyView Answer on Stackoverflow
Solution 6 - AndroidJames McCrackenView Answer on Stackoverflow
Solution 7 - AndroidGeraldo NetoView Answer on Stackoverflow
Solution 8 - AndroidSUPERYAOView Answer on Stackoverflow
Solution 9 - Androiduser1354603View Answer on Stackoverflow
Solution 10 - AndroidGilbertView Answer on Stackoverflow
Solution 11 - AndroidShailesh Mani PandeyView Answer on Stackoverflow
Solution 12 - AndroidZar E AhmerView Answer on Stackoverflow
Solution 13 - AndroidArstView Answer on Stackoverflow
Solution 14 - Androidحسن ستاریView Answer on Stackoverflow
Solution 15 - AndroidGerardo SuarezView Answer on Stackoverflow
Solution 16 - AndroidolajideView Answer on Stackoverflow
Solution 17 - Androidalierdogan7View Answer on Stackoverflow
Solution 18 - AndroidNickUnuchekView Answer on Stackoverflow