Communicate from Activity to Fragment using Interface - java

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.
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.

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.

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

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);
}
}

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. **/
}
}
...
}

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.

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)'

Related

How to use interface to communicate between fragment and activity?

I simply want to call a Fragment method from my MainActivity.
So I tried to use an Interface.
public interface MyInterface {
void testMethod();
}
In my Fragment (TestFragment.java) I implement the interface and overrite the testMethod method.
#Override
public void testMethod() {
Toast.makeText(getActivity(), "Test", Toast.LENGTH_LONG).show();
}
but now I want to call this method from my MainActivity as soon as the onRewardedVideoCompleted get's called, but I'm not sure how to do it.
I tried it like this:
MyInterface myInterface = new TestFragment();
myInterface.testMethod();
But here I get an nullPointerException:
Attempt to invoke virtual method 'java.lang.String
android.content.Context.getPackageName()' on a null object reference
Which reffers to the Toast message.
How do I call the method from my Interface in my MainActivity without getting an NullPointerException?
Thanks
You need to create the interface for it like below
public interface FilterValuePassInterface {
public void onSelectedFilterValue(String name);
}
Fragment class should look like below
class MyFragment extends Fragment implements FilterValuePassInterface {
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
((YOUR_ACTIVITY) getActivity()).setOnDataListener(this);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void onSelectedFilterValue(String name) {
}
}
And inside the Activity class , you need to create the method setOnDataListener and initialise the fragment like below
MyFragment myFragment;
public void setOnDataListener(MyFragment myFragment) {
this.myFragment = myFragment;
}
Again inside the activity you can send the data from any click or event, you just need to call this method from the activity to transfer the data in fragment like below
YOUR_CLICK.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
myFragment.onSelectedFilterValue("YOUR_MSG");
}
});
If you want to access your method from Activity to Fragment. You do not need any interface. You just need to call the method from the fragment instance. However, if you want access Activity's method, you may use the interface.
public interface MyInterface {
void testMethod();
}
And in your activity,
class MyActivity implements MyInterface{
void testMethod(){
}
}
in your fragment,
class MyFragment extends Fragment{
MyInterface myInterface;
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity() instanceof MyActivity) {
myInterface = (MyInterface) getActivity();
}
}
public interface MyInterface {
void testMethod();
}
class MyActivity implements MyInterface{
public void testMethod(){
}
}
Inside your main(), you can create a new object of MyActivity like this which will allow you to access the method:
MyActivity example= new MyActivity();
example.testMethod();

A listener to a fragment without calling the fragment in android

Im calling a fragment(ImageFraggment) from an actvity(MainActivity) , and created a interface on that fragment. And also i have implement Listner in Main activity. you can see the code below.
MainActivity.java
public class MainActivity extends AppCompatActivity implements ImageFragment.imageEventListener {
//Calling ImageFragment
#Override
public void eventListner(int number) {
log.d("MainActivity",number);
}
}
ImageFragment.java
public class ImageFragment extends Fragment {
private imageEventListener imageEventListener;
//enter a number
//if number equal to 1
{
imageEventListener.eventListner(number);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
imageEventListener = (imageEventListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement imageEventListener");
}
}
public interface imageEventListener {
void eventListner(int number);
}
}
This code works fine, means when user enters 1,log will display it(from mainActivity).
But now im trying to Listen to same event from another activity(AnotherActivity)(which doesnot call ImageFragment) as shown in below code.
AnotherActivity.java
public class AnotherActivity extends AppCompatActivity implements ImageFragment.imageEventListener {
//I dont call imageFragment here
#Override
public void eventListner(int number) {
log.d("AnotherActivity",number);
}
}
But im unable to print the number using log, How can i resolve this?I'm missng any major thing here?
At first, it will help you if you know the observer pattern: https://sourcemaking.com/design_patterns/observer
According to the observer pattern:
ImageFragment is a subject.
MainActivity and AnotherActivity are observers.
If you want to listen to an event from the subject, you need to register the observers first.
Look at your ImageFragment:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
imageEventListener = (imageEventListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement imageEventListener");
}
}
In here, you have registered only MainActivity(you said that: "which doesn't call ImageFragment"), for this reason, you will not able to listen to that event from that activity if you don't call/start that Imagefragment from that activity.
Thank you.

Setting context on custom listener in a dialog

I created a very simple listener interface that looks like this:
public interface ReportDialogListener {
void shouldRemoveBlockedUser();
}
Now, in my ReportDialog class which is defined like this:
public class ReportDialog extends Dialog implements View.OnClickListener {}
I want to implement this listener and send callback for a certain action. However, when I do send callback after a certain action... my mDialogListener variable is null.
Where do I set the context?
This is what I tried:
private ReportDialogListener mDialogListener;
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
try {
mDialogListener = (ReportDialogListener) getContext();
} catch (ClassCastException e) {
}
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mDialogListener = null;
}
But when I call mDialogListener.shouldRemoveBlockedUser();, mDialogListener is null...
Also- I made sure my main activity was implementing ReportDialogListener... thanks
Implement Listener in MainActivity
Public class MainActivity implements ReportDialogListener {
ReportDialogListener reportDialogListener ;
public void onCreate(Bundle saveInstanceState){
reportDialogListener =this;
}
#override
public void shouldRemoveBlockedUser(){
}
}
Pass reportDialogListener object to other class or activity and call the listener method reportDialogListener.shouldRemoveBlockedUser();
If this main activity implements the interface, do not use the activity context. Use this instead. mDialogListener = this;
Also i do not see where you implement the interface,only the View onClick interface you have actually implemented.
public class ReportDialog extends Dialog implements View.OnClickListener
to
public class ReportDialog extends Dialog implements View.OnClickListener,ReportDialogListener
To implement the interface in another, either you define it in the constructor of the calling program, or devise a method that does it.
Since my main activity was actually sending this when creating an instance of ReportDialog :
if (mReportDialog == null) {
mReportDialog = new ReportDialog(this);
}
I was able to assign it to a variable in the constructor of ReportDialog
public ReportDialog(Activity activity) {
super(activity);
mActivity = activity;
init();
}
Then, use it like this:
mDialogListener = (ReportDialogListener) mActivity;
Works perfectly.

method call from adapter class to activity

Adapter:
check_list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JPrequirements.prepareSelection(v, getAdapterPosition());
}
});
JPrequirements is the activity. and prepareSelection is non-static method inside activity. I cannot access it from adapter.
ERROR:
non static method cannot be referenced from a static context
Which is right. that's why I tried with:
JPrequirements().prepareSelection(v, getAdapterPosition()); // Creating an instance...
But, the problem is I lost all activity component here. eg. layout components and other supporting variables. I don't want that. What is the best way to deal with this? How can I get updated value from adapter to activity? So, I can display it real-time.
Thanks.
You can achieve this via interface. Firstly, define an interface class as:
public interface ActivityAdapterInterface {
public void prepareSelection(View v, int position);
}
Now, implement the interface in your Activity as:
public class JPrequirements extends AppCompatActivity implements ActivityAdapterInterface {
...
public void prepareSelection(View v, int position) {
// cool stuff here
}
...
}
Make sure you pass this interface reference to your Adapter via its constructor. Then finally call it on click as:
check_list_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mActivityAdapterInterface.prepareSelection(v, getAdapterPosition());
}
});
[EDIT]
To provide the interface to your Adapter provide it the constructor.
public class YourAdapter ... {
private ActivityAdapterInterface mActivityAdapterInterface;
public YourAdapter(..., ActivityAdapterInterface activityAdapterInterface) {
activityAdapterInterface = mActivityAdapterInterface;
}
}

Share a fragment with several classes?

I wonder how I can best create a progress bar fragment. It must be usable by every other class of course.
At the moment I have just a ProgressBarFragment, which has public setVisible method. Getting the Fragment through FragmentManager I can set it visible or not. But is this the right way to do these sort of actions?
public class MyActivity exetends FragmentActivity {
void setVisibility(int visible) {
ProgressBarFragment fragment = (ProgressBarFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_progress_bar);
fragment.setProgressBar(visible);
}
}
And of course I have several other Fragments which uses this code too, to trigger the progress bar.
public class ProgressBarFragment extends Fragment {
public void setProgressBar(int visible) {
progressBar = (ProgressBar) getActivity().findViewById(R.id.progress_bar);
progressBar.setVisibility(visible);
}
}
You can refactor this code into a static method of your ProgressBarFragment
class ProgressBarFragment {
//...
static void setVisibility(Activity parent, int visible) {
ProgressBarFragment progressBar =
(ProgressBarFragment)parent.getSupportFragmentManager()
.findFragmentById(R.id.fragment_progress_bar);
progressBar.setProgressBar(visible);
//...
}
So then you will be using ProgressBarFragment.setVisibility(yourActivity, 1) everywhere.

Categories