3

I am using a drop-down menu with the different items in the toolbar. In the activity, I am adding the fragment as soon as the menu item is clicked. The fragment OnCreateview gets called and the data is fetched from the API. The logic for the fetching of data remains same for all menu items but only the API endpoint differs. So I am trying to pass the Bundle with API endpoint name and using the same fragment for all the items. But the problem is OnCreateView gets called only first time and the request is made only for first fragment transaction even if I am replacing the same fragment for different item click.

Activity.java

    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
    switch (i) {
        case 0: //Clients
            Bundle bundle1 = new Bundle();
            bundle1.putString("hash-key","item1");
            ReportCategoryFragment rp1 = new ReportCategoryFragment();
            rp1.setArguments(bundle1);
            replaceFragment(rp1,false,R.id.container);
            break;

        case 1:
            Bundle bundle2 = new Bundle();
            bundle2.putString("hash-key","item2");
            ReportCategoryFragment rp2 = new ReportCategoryFragment();
            rp2.setArguments(bundle2);
            replaceFragment(rp2,false,R.id.container);
            break;
      }
     }

ReportCategoryFragment

    @Nullable
@Override
public View onCreateView(LayoutInflater inflater,
                         @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    rootView = inflater.inflate(R.layout.fragment_runreport, container, false);
    setHasOptionsMenu(true);
    ButterKnife.bind(this, rootView);
    presenter.attachView(this);
    reportType = getArguments().getString("hash-key");
    Log.v("hashkey",reportType);
    presenter.fetchCategories(reportType, false, true);

    return rootView;
}

replaceFragment Function

     public void replaceFragment(Fragment fragment, boolean addToBackStack, int containerId) {
    invalidateOptionsMenu();
    String backStateName = fragment.getClass().getName();
    boolean fragmentPopped = getSupportFragmentManager().popBackStackImmediate(backStateName,
            0);

    if (!fragmentPopped && getSupportFragmentManager().findFragmentByTag(backStateName) ==
            null) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(containerId, fragment, backStateName);
        if (addToBackStack) {
            transaction.addToBackStack(backStateName);
        }
        transaction.commit();
    }
}

EDIT: FragmentnewInstance method

     public static ReportCategoryFragment newInstance() {
    ReportCategoryFragment fragment = new ReportCategoryFragment();
    Bundle bundle = new Bundle();
    fragment.setArguments(bundle);
    return fragment;
}
Bersh
  • 2,789
  • 3
  • 33
  • 47
Falcon
  • 372
  • 4
  • 20
  • use singleton fragment and pass values in its constructor – Quick learner Jun 12 '18 at 06:19
  • https://stackoverflow.com/questions/14839152/fragment-as-a-singleton-in-android?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Quick learner Jun 12 '18 at 06:19
  • @quicklearner In the accepted answer it's mentioned that "Fragments are meant to be reusable components of applications. You should not be using them as singletons". Any other possible solution? – Falcon Jun 12 '18 at 06:31
  • i think if you want to use same fragment you can use singleton class so it keeps a single instance and You can use Interface and Broadcast reciever for your requiremnt – Quick learner Jun 12 '18 at 06:38
  • Yes, I want to use the same fragment but I want the oncreateview to be called on each menuItem click since I am passing different bundle parameter for which I need different API call in oncreateview hence resulting in different layout. – Falcon Jun 12 '18 at 06:42
  • please check my answer – Quick learner Jun 12 '18 at 06:48

2 Answers2

0

Try using static method in fragment to create new instance of the fragment.

public static Fragment newInstance() 
{
    MyFragment myFragment = new MyFragment();
    return myFragment;
}
  • refer https://stackoverflow.com/questions/9245408/best-practice-for-instantiating-a-new-android-fragment for more details – ashikvashraf Jun 12 '18 at 06:34
0

Simple solution is to use Broadcast Receiver Declare this in your fragment class

BroadcastReceiver broadCastNewMessage = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
           //extract our message from intent
            String msg_for_me = intent.getStringExtra("some_msg");

        }
    };

Now in onCreate() of fragment register this

registerReceiver(this.broadCastNewMessage, new IntentFilter("update_fragment"));

And in onDestroyView()

unregisterReceiver(broadCastNewMessage);

Now Call this method from the service class where u want to update the activity from your menu selection

Intent intent = new Intent("update_fragment");
intent.putExtra("some_msg", message); 
sendBroadcast(intent);
Quick learner
  • 10,632
  • 4
  • 45
  • 55
  • This helps in passing the message but the catch is **presenter.fetchCategories(reportType, false, true);** in oncreate view. This approach does not force oncreate view to be called again when I replace the fragment with itself. If Oncreate View is not called again, how can I redraw the layout with the passed parameters? – Falcon Jun 12 '18 at 07:20
  • you can call this in onreceive presenter.fetchCategories(reportType, false, true); – Quick learner Jun 12 '18 at 07:22
  • do you have single layout or multiple? – Quick learner Jun 12 '18 at 07:22
  • Single layout with recycler view. I'll make the changes and would let you know if this works. Thanks a lot. – Falcon Jun 12 '18 at 07:59
  • One more thing, do I need to call **replaceFragment(new ReportCategoryFragment(),false,R.id.container);** in every switch case along with sendBroadcast? – Falcon Jun 12 '18 at 08:16
  • No need to do call that ,just send broadcast to fragment class it will automatically call on receive – Quick learner Jun 12 '18 at 09:02
  • It works but I am curious if there is a way by which fragment can be redrawn on replacing it with itself? – Falcon Jun 12 '18 at 11:13
  • since that suit my requirements according to the UC – Falcon Jun 12 '18 at 11:25
  • i am glad it worked for you , is everything working for you? – Quick learner Jun 12 '18 at 11:32
  • i think there is no need to do that when you just want to call api or updates views simply , to replace fragment you will also need to check fragment is already added in backstack or not , which is not a good thing to implement to just call api or update view :) – Quick learner Jun 12 '18 at 12:11
  • Yes it is working but as soon as I fetch the item from API and click on it to open another fragment and then press back button to come to the fetched item fragment and then pressing another item from menubar results in no call to broadcast reciever and nothing changes,moreover when i press the back button i get the error **cannot resolve method register reciever**. Anyways That should be other problem,i guess? – Falcon Jun 12 '18 at 12:41
  • okay then dont unregister the receiver in on destroy view and in your api method in response method , just check whether the fragment is visible or not , take a boolean , make it true in on create and make it false on ondestroy view then check if boolean is true then update the view in on response method, And yes this is a another issue – Quick learner Jun 12 '18 at 12:51
  • dont worry i am here to help you :) – Quick learner Jun 12 '18 at 12:51
  • Thanks for the help, I'll try that out. I'll accept your answer.Thanks for the patience, I'll ask you if i get stuck. – Falcon Jun 12 '18 at 12:54