16

I have this interface in my activity.

public interface LogoutUser {
    void logout();
}

My fragment implements this interface, so in my fragment, I have this:

@Override
public void logout() {
    // logout
}

In my activity I call

mLogoutUser.logout();

Where mLogoutUser is of the type LogoutUser interface.

My issue is the mLogoutUser object that is null. How can initialize it?

Thank you!

androidevil
  • 9,011
  • 14
  • 41
  • 79

4 Answers4

21

As I said in my comment, I resolved this issue using onAttach method in my fragment, but in this way you have to have the callback field (mLogoutUser in this case) declared in the fragment, and initialize it this way:

public class MyFragment extends ListFragment {
    LogoutUser mLogoutUser;

    // Container Activity must implement this interface
    public interface LogoutUser {
        public void logout();
    }

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

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mLogoutUser = (LogoutUser) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement LogoutUser");
        }
    }

    ...
}

More info in Communicating with Other Fragments.


But if your case is the field declared in the activity, you can use the onAttachFragment method from your activity to initialize your listener field this way:

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

    mLogoutUser = (LogoutUser) fragment;
}

Also, you can use an event bus to make this communication between fragments and activities. An option is the Otto library, from Square.

Mohsin
  • 1,586
  • 1
  • 22
  • 44
androidevil
  • 9,011
  • 14
  • 41
  • 79
  • 1
    Thanks a ton @androidevil. You saved my day! BTW if we have multiple fragments attached we can you if(fragment instanceof fragmentone){} in onAttachFragment. – Kishore Oct 30 '15 at 15:01
  • This is not the best way, You are violating the OpenClose principle. Actually, if you want to reuse this fragment in other activities because of instance checking that you are doing, You can't do that – Ehsan Apr 16 '19 at 09:46
  • With onAttach(Activity activity) being deprecated, and onAttach(Context context) now available, I think the initial suggestion is now acceptable. – C. Skjerdal Jan 12 '20 at 15:32
16

Sample for creating callback from Fragment to Activity

public interface CallBackListener {
    void onCallBack();// pass any parameter in your onCallBack which you want to return
}

CallBackFragment.class

public class CallBackFragment extends Fragment {

    private CallBackListener callBackListener;

    public CallBackFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        return inflater.inflate(R.layout.fragment_call_back, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //getActivity() is fully created in onActivityCreated and instanceOf differentiate it between different Activities
        if (getActivity() instanceof CallBackListener)
            callBackListener = (CallBackListener) getActivity();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Button btn = (Button) view.findViewById(R.id.btn_click);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(callBackListener != null)
                    callBackListener.onCallBack();
            }
        });
    }
}

CallbackHandlingActivity.class

public class CallbackHandlingActivity extends AppCompatActivity implements CallBackListener
{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_all_user);

    }

    @Override
    public void onCallBack() {
        Toast.makeText(mContext,"onCallback Called",Toast.LENGTH_LONG).show();
    }
}
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
5

Android Fragments - Communicating with Activity

You need to get a reference to your fragment with getFragmentById() or getFragmentByTag()

getFragmentManager().findFragmentById(R.id.example_fragment);
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Erik Nedwidek
  • 6,134
  • 1
  • 25
  • 25
0

You can use kotlinx Channel to send data or callback between fragments and activity or vice versa

In your Mainactivity:

val loginPromptChannel = Channel<LoginPromptState>()
val loginStateFlow = loginPromptChannel.receiveAsFlow()

//onCreate
lifecycleScope.launchWhenStarted {
            loginStateFlow.collect() { state ->
                when (state) {
                    is LoginPromptState.Login -> {
                        //smooth scroll to login fragment
                        binding.viewpager.setCurrentItem(2, true)
                    }

                }
            }
        }
//create sealed a class 
sealed class LoginPromptState {
        object Login : LoginPromptState()
    }

In your fragment send callback like:

lifecycleScope.launch {
    val channelLogin = (activity as MainActivity).loginPromptChannel
    channelLogin.send(MainActivity.LoginPromptState.Login)
}
nhCoder
  • 451
  • 5
  • 11