6

I have searched SO for this problem but was not able to find anything which would solve my problem. My problem is, I have a activity which contains FrameLayout which is constantly updated with different fragments. The top view and bottom view are going to remain same hence they are in the layout of the activity.

As you can see bottom view has a button on click of that i want to make changes in the fragments which will be present in the FrameLayout.

enter image description here

I have created a interface

public interface ShowFormula {

    void showFormula(boolean show);

}

which i will use to implement in the fragment. Now the main problem in my MainActivity class i am trying to initialize the interface but not able to as i am getting class cast exception

showFormula = (ShowFormula) this;//yes i know this is wrong

How should i initialize this in order to communicate with the fragment. Main goal is to toggle the view in fragments on click of the button in activity.

Thanks in advance.

Swapnil Kadam
  • 4,075
  • 5
  • 29
  • 35
  • 1
    Implement your interface on the fragment and assign it to your interface variable on fragment creation. You are doing it in reverse order it doesnt make sense to store a reference to this and it crash because you have implemented the interface in the fragment (Thats OK). – Nanoc Nov 11 '15 at 16:34
  • but how will i get button click listener event in fragment as the button is present in the layout of the activity. Thats y i have tried to implement in reverse order, so when user clicks on the button present in the activity i could toggle visibility of the view present in the fragment. – Swapnil Kadam Nov 11 '15 at 16:40
  • Use the interface to notify your fragment of the button click – Nanoc Nov 11 '15 at 16:41
  • 2
    You don't need to use an interface to make calls from an activity to a fragment. Just keep a reference to the current fragment, and call into a public method in the fragment. – Daniel Nugent Nov 11 '15 at 16:44
  • yes that's what i was trying to do but i am getting class cast exception in Activity as i am not able to initialize the interface. Please refer to the last code snippet in my question. :) – Swapnil Kadam Nov 11 '15 at 16:45
  • @DanielNugent ok i will try it that way and let you know. – Swapnil Kadam Nov 11 '15 at 16:50
  • @DanielNugent thanks it worked, i did upvote your answer but how should i accept your answer? – Swapnil Kadam Nov 11 '15 at 17:20
  • @Swapnil Great, glad it worked for you! Just added an answer with a little more info as well. – Daniel Nugent Nov 11 '15 at 18:34

6 Answers6

19

You don't need to use an interface to make calls from an Activity to a Fragment. Just keep a reference to the current Fragment, and call into a public method in the Fragment from the Activity.

If you have multiple Fragments and you don't want to keep a reference for each one, you can create a Fragment base class, declare the common method in the base class, and then implement that method override in all of your Fragments that inherit from the base Fragment. Then, keep one reference of the base Fragment type, and always have it set to the Fragment that is shown currently.

Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
6

Activity ---> Fragment

Communication from Activity to Fragment is pretty straightforward. You really don't need a listener.

Let's say you have a method inside Fragment share()

public class MyFragment extends Fragment{

   public static MyFragment getInstance()
   {
       return new MyFragment();
   }

   ........

   public void share()
   {
        // do something
   }

}

How to call share() method from an Activity?

Get the reference of the Fragment and call the method. Simple!

MyFragment myFragment = MyFragment.getInstance();
myFragment.share();

You can see the full working code for Fragment to Fragment Communication

Rohit Singh
  • 16,950
  • 7
  • 90
  • 88
  • I was trying to show a minimal code. getInstance() is how you instantiate a Fragment. But for you I have updated the code. @user1804084 . Go through the git repository for better understanding. – Rohit Singh Jan 23 '19 at 15:01
  • If you are wondering why I create instance this way. You can read this post https://stackoverflow.com/questions/9245408/best-practice-for-instantiating-a-new-android-fragment – Rohit Singh Jan 23 '19 at 15:03
  • Editext Value Getting Null when I call from Activity to Fragment. can you please help me – Sayed Rizwan Hashmi May 08 '21 at 10:59
1

Just to add to Daniel Nugent's brilliant answer, here are snippets from my working code for delegating calls from Activity to Fragment.

I have a MVP architecture and I have defined the error handling method showError on the BaseView class and the code below demonstrates how to handle the UI on a TargetFragment class. I, specifically needed to hide my progress spinner on the fragment upon any error scenario. Here's the code snippets for the base classes:

public interface BaseView {
   void showError(ErrorResponse errorResponse);
}

public abstract class BaseActivity implements BaseView {
   @Override
   public void showError(ErrorResponse errorResponse) {
       // Check error condition or whatever
       // ...
       MaterialDialog dialog = new MaterialDialog.Builder(this)
                .title(R.string.dialog_error_title)
                .content(R.string.error_no_internet)
                .positiveText(R.string.dialog_action_ok)
                .build();
       dialog.show();
   }
}

public abstract class BaseFragment implements BaseView {
   @Override
   public void showError(ErrorResponse errorResponse) {
      ((BaseView) getActivity()).showError(errorResponse);
   }
}

And, this is how I handle UI inside my TargetFragment class:

public final class TargetFragment extends BaseFragment implements TargetView {
   @Override
   public void showError(ErrorResponse errorResponse) {
        super.showError(errorResponse);
        hideSpinner();
        
        // Do other UI stuff
        // ...
   }

   private void hideSpinner() {
       spinner.setVisibility(View.INVISIBLE);
   }
}
Prince
  • 20,353
  • 6
  • 39
  • 59
0

a clean solution:

public interface ShowFormula {
   public void showFormula(boolean show);
 }  

public class MyActivity implements ShowFormula {
   ...
   @Override
   public void showFormula(boolean show) {
     /** Your Code **/
   }
   ...
 }

public class MyFragment {
   private ShowFormula listener;
   ...
   @Override
   public void onAttach(Activity activity) {
     super.onAttach(activity);
     try {
       listener = (ShowFormula) activity;
       // listener.showFormula(show?);
     } catch (ClassCastException castException) {
       /** The activity does not implement the listener. **/
     }
   }
   ...
 }
Aman Kumar
  • 23
  • 4
jMike
  • 307
  • 4
  • 12
0

simple thing make public method in fragments then call it on from your activity. e.g

MyFragment fragment = new MyFragment(); fragment.doSomeThing();

doSomeThing() is a public method in MyFragment.

vishwajit76
  • 2,300
  • 20
  • 16
-2

Activity to Fragment Communication via Interface:

public class MyActivity {

   private ShowFormula showFormulaListener;

   public interface ShowFormula {
      public void showFormula(boolean show);
  }

  public void setListener(MyFragment myFragment) {
      try {
      showFormulaListener = myFragment;
      } catch(ClassCastException e) {
     }
   }
 }

public class MyFragment implements ShowFormula{

     @Override
     public void onAttach(Activity activity) {
       super.onAttach(activity);
       try {
        ((MyActivity) activity).setListener(this);
        } catch (ClassCastException e) {
        Log.e(TAG, e.toString());
    }
}
     @Override
     public void showFormula(boolean show) {
     /** Your Code **/
     }
}

Once you are done setting this, you can call 'showFormulaListener.showFormula(boolVal)'

Anubhav
  • 1,984
  • 22
  • 17