Handling onNewIntent in Fragment
android, android-fragments, android-intent
Solution
This is an old question, but let me answer it in case anybody bumps into it.
First of all you have a bug in your code:
You can't register `Fragments` as listeners inside `Activity` the way you do it. The reason is that `Activity` and `Fragments` can be destroyed by the system and re-created later from saved state (see documentation on Recreating an Activity). When this happens, new instances of both the `Activity` and the `Fragment` will be created, but the code that sets the `Fragment` as a listener will not run, therefore `onNewBalanceRead()` will never be called. This is very common bug in Android applications.
In order to communicate events from `Activity` to `Fragment` I see at least two possible approaches:
Interface based:
There is an officially recommended approach for communication between Fragments. This approach is similar to what you do now in that it uses callback interfaces implemented by either `Fragment` or `Activity`, but its drawback is a tight coupling and lots of ugly code.
Event bus based:
The better approach (IMHO) is to make use of event bus - "master component" (`Activity` in your case) posts "update" events to event bus, whereas "slave component" (`Fragment` in your case) registers itself to event bus in `onStart()` (unregisters in `onStop()`) in order to receive these events. This is a cleaner approach which doesn't add any coupling between communicating components.
All my projects use Green Robot's EventBus, and I can't recommend it highly enough.
Problem
I am writing an application that uses NFC to read some data stored on it. My application uses Fragments and Fragment don't come with onNewIntent() method. Since, the data I am reading is done with my separate class which handles NFC related operation, the only thing I need to do is update the TextView inside the Fragment. However this implementation can also be used to pass new Intent to the Fragment. Here is my current implementation which makes use of an interface. I am calling the listener after new Intent is received and NFC related checks succeeds. This is the FragmentActivity which hosts Fragment. ``` public class Main extends FragmentActivity implements ActionBar.OnNavigationListener { private Bundle myBalanceBundle; private NFC nfcObj; private NewBalanceListener newBlanceListener; @Override public void onNewIntent(Intent intent) { setIntent(intent); } @Override protected void onResume() { getNFCState(); super.onResume(); } private void getNFCState() { //Other NFC related codes else if (nfc_state == NFC.NFC_STATE_ENABLED){ readNFCTag(); } } private void readNFCTag() { //Other NFC related codes if (getIntent().getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) { nfcObj.setTag((Tag) getIntent().getParcelableExtra( NfcAdapter.EXTRA_TAG)); nfcObj.readQuickBalance(); transitQuickReadFragment(nfcObj.getCurrentBalance()); } } private void transitQuickReadFragment(String balance) { // Creates a balance bundle and calls to select MyBalance Fragment if it // is not visible. Calls listener is it is already visible. if (actionBar.getSelectedNavigationIndex() != 1) { if (myBalanceBundle == null) myBalanceBundle = new Bundle(); myBalanceBundle.putString(Keys.BALANCE.toString(), balance); actionBar.setSelectedNavigationItem(1); } else { newBlanceListener.onNewBalanceRead(balance); } } @Override public boolean onNavigationItemSelected(int position, long id) { // Other fragment related codes fragment = new MyBalance(); fragment.setArguments(myBalanceBundle); newBlanceListener = (NewBalanceListener) fragment; // Other fragment related codes } // Interface callbacks. You can pass new Intent here if your application // requires it. public interface NewBalanceListener { public void onNewBalanceRead(String newBalance); } } ``` This is MyBalance Fragment which has TextView that needs to be updated whenever NFC is read: ``` public class MyBalance extends Fragment implements NewBalanceListener { private TextView mybalance_value; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //Other onCreateView related code Bundle bundle = this.getArguments(); if (bundle != null) mybalance_value.setText(bundle.getString(Keys.BALANCE.toString(), "0.00")); else mybalance_value.setText("0.00"); //Other onCreateView related code } @Override public void onNewBalanceRead(String newBalance) { mybalance_value.setText(newBalance); } } ``` This code works perfectly like expected for my application but, I want to know if there is better way to handle new Intent from Fragments?