0

I have activity and two fragments which opened in this activity (for example FragmentFirst, FragmentSecond). In my activity I register BroadcastReceiver. And when i receive any event (inside onReceive) I need to display the received text in the TextView of second fragment.

I could register the BroadcastReceiver in the second fragment, however, the event may come at the moment when my second fragment opens and then I do not have time to register the BroadcastReceiver and I lose the event.

So my code inside the onReceive of activity looks like this:

        @Override
        public void onReceive(Context context, Intent intent) {
            String receivedMessage = intent.getStringExtra(MY_MESSAGE);
            Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
            if (currentFragment instanceof FragmentSecond) {
                ((FragmentSecond) currentFragment).initMessage(receivedMessage);
            }
        }

And now I have a question, can there be such a situation that the current fragment is FragmentSecond, but the view of this fragment has not yet been created. In this case, I can get a NPE when calling a initMessage of my FragmentSecond that sets the receivedMessage for the TextView.

If this is really possible, then I will have to add some kind of checks inside the initMessage:

public void initMessage(String receivedMessage) {
    if (isViewCreated) { // flag to detect when view was created
        tvMessage.setText(receivedMessage);
        savedMessage = "";
    } else {
        savedMessage = receivedMessage; // save message to display it when view will be created
    }
}

In practice, I was not able to reproduce such a situation, but it seems to me that this is possible. Please tell me if this is possible?

P.S. I get the feeling that the onReceive controls the life cycle and is called exactly when the fragment view is created. Because I tried to send a broadcast until the moment when the FragmentSecond view was created, but until the onViewCreated of my FragmentSecond was called, onReceive was not called. However, I may be wrong

testivanivan
  • 967
  • 13
  • 36
  • What scope do you intend for the receiver to have? Is it only for the Activity and what is scope for the value that you receive from the receiver(Are you interested only in the latest value or do you need all of the sequence)? – TheLibrarian Oct 17 '22 at 10:21
  • if you are using kotlin you can use lamda function to invoke and receive in repective fragment. But obviously if fragment view has been created and not destroyed it can update the fragment UI – Raza Oct 17 '22 at 10:24
  • @Raza, unfortunately I am using Java – testivanivan Oct 17 '22 at 10:58
  • @TheLibrarian, I 'm interested only in the latest value – testivanivan Oct 17 '22 at 10:59

1 Answers1

1

You can store the message in the Activity and use it the fragment WHEN fragment is ready.

Activity

    String message = null; 

    @Override
    public void onReceive(Context context, Intent intent) {
        message = intent.getStringExtra(MY_MESSAGE);
    }

You can "touch" the Activity in onAttach(context) method of the fragment.

Fragment

    private String message = null;

    void onAttach(Context: context) {
        super.onAttach(context)
        if (context instanceof MainActivity) {
            MainActivity mainActivity = (MainActivity) context;
            message = mainActivity.message;
        }
    }

That is for grabbing the latest value.

Since you are operating in Java is it a bit more verbose but for updates you can use Observer pattern(create listener interface which the fragments will implement and register themselves to the activity).

interface MessageObserver {
    void onMessageChange(String message);
}

Use WeakReference for the Activity so it doesn't leak the context.

Fragment

    private WeakReference<MainActivity> mWeakRefActivity;

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (context instanceof MainActivity) {
            MainActivity mainActivity = (MainActivity) context;
            mWeakRefActivity = new WeakReference<MainActivity>(mainActivity);
            mainActivity.addObserver(this);
        }
    }

    @Override
    public void onDetach() {
        // Clean up after yourself
        mWeakRefActivity.get().removeObserver(this);
        super.onDetach();
    }

Activity

    ArrayList<MessageObserver> mObservers = new ArrayList<MessageObserver>();

    void addObserver(MessageObserver observer) {
        mObservers.add(observer);
    }

    void removeObserver(MessageObserver observer) {
        mObservers.remove(observer);
    }

    public void onReceive(Context context, Intent intent) {
        message = intent.getStringExtra(MY_MESSAGE);
        for (MessageObserver observer : mObservers) {
            observer.onMessageChange(message);
        }
    }
TheLibrarian
  • 1,540
  • 1
  • 11
  • 22