How to interface two different fragments from one activity - android

I have two different layouts, for two different fragments, but in single activity. I am using onAttachFragment callback, but I am unable to use both the interfaces simultaneously.
public interface AvInterface{
public void onMessageRead(String data);
}
public interface WeInterface{
public void onMessageRead(String data);
}
somefunction(){
avInterface.onMessageRead("14221322345124");
weInterface.onMessageRead("142620405958");
}
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
try {
avaInterface = (AvInterface) fragment;
weInterface = (WeInterface) fragment;
}
catch (ClassCastException e) {
//throw new ClassCastException(fragment.toString()+" must override AvInterface");
}
}

You should use the onAttach() callback in Fragment.
From onAttachFragment() doc :
Called when a fragment is attached as a child of this fragment.
This is a callback provided when you attach a child fragment is attached to the current fragment.
I think you are hosting both fragments in the activity and hence use onAttach() to get access to the interface to communicate with the activity.

Like mentioned by #Arka Prava Basu, you only need one Interafce and you do something like the following in your parent activity
if(fragment InstanceOf fragmentA){
dosomething();
}else{
dosomethingelse()
}
I hope you get the idea.

Related

Transfer data using Bundles from Fragment to Fragment and read it from another Fragment using same key

I have 4 fragments in my app.On First Fragment based on some conditions I am transferring data from Fragment First to Third or Fourth.I am passing the data, and reading the data using Bundles with same Key names all over Fragments.
But I am not able to receive data send from Fragments send by other screens.
This is code for condition and send data using Bundle from Fragment First
saveSession.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(feedbackAction.equals("rating_good")) {
bundle.putString("id", myId);
bundle.putString("No", no);
fdb.setArguments(bundle);
tx = fm.beginTransaction();
tx.replace(R.id.frame,fdb);
tx.addToBackStack("TabInfo");
tx.commit();
} else if(feedbackAction.equals("rating_bad")) {
bundle.putString("id", myId);
bundle.putString("No", no);
fdb.setArguments(bundle);
tx = fm.beginTransaction();
tx.replace(R.id.frame,bfd);
tx.addToBackStack("TabInfo");
tx.commit();
}
}
});
This is code for retrieving data from Second Fragment
id=getArguments().getString("id");
my_no=getArguments().getString("No");
This is code to retrieve data from Fourth Fragment
id=getArguments().getString("id");
my_no=getArguments().getString("No");
But I am getting error as
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.BaseBundle.getString(java.lang.String)' on a null object reference
How to get retrieve this Bundle data in other Fragments with Same Key ?
As a general rule you can follow, use fragments for ui and handle fragment, activity changes in activity. What you can do is to create an interface and implement that interface in your activity that uses the fragment like this.
public interface OnActionClickedListener {
void onSessionClicked(String name);
}
In your fragment, you need to initialize this listener.
OnActionClickedListener onActionClickedListener;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onActionClickedListener = (MyFragment.OnActionClickedListener) context;
} catch (Exception e) {
throw new ClassCastException();
}
}
Now in your onClickListener on fragment you can just call
onActionClickedlistener.onSessionClicked("string you want to enter");
And at last your activity should extend MyFragment.OnActionClickedListener and implement the method onSessionClicked where you will change the fragment displayed. You can easily reach the data hold in activity from fragment. This way if another activity uses your fragment, that activity can also implement the onActionClickedListener according to it's needs.

Android Nested Fragment and Interface

I have a Fragment A which has an interface that will return the value of a TextView. The Fragment A is initialized and Attached to FragmentB. Here is the code for Fragment A and B.
Fragment A
public class FragmentA extends Fragment {
...
public interface Listener {
void onValue(int value);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof Listener) {
listener = (Listener) context;
} else {
throw new RuntimeException(context.toString() + " must implement Listener");
}
}
}
Fragment B
public class FragmentB extends Fragment implements FragmentA.Listener {
...
private void initFragmentA() {
FragmentManager fragmentManager = getChildFragmentManager();
fragmentA = FragmentA.newInstance();
fragmentManager.beginTransaction().add(container, fragmentA, TAG).commit();
}
#Override
public void onValue(int value) {
}
}
When I start the app, a error occurred:
Java.lang.RuntimeException: ####.page.MainActivity#1f7f316c must implement Listener
at ####.widget.FragmentA.onAttach(FragmentA.java:66)
The MainActivity contains the Fragment B, but the Fragment B has already implemented the interface of Fragment A. Why the error occurred? The interface implemented in parent Fragment doesn't work?
From Android Developer website, it says:
Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Therefore, when you implement that interface in Fragment B, it throws a RuntimeException error.
Summary: you have to implement that interface in your fragment hosting activity.
You can learn more on how to pass data between fragments thru a hosting activity (usually we make use of Bundle) at http://www.vogella.com/tutorials/AndroidFragments/article.html
The error message is pretty clear. When you use onAttach, the context passed through is actually the host Activity - the biggest boss of all, not the parent fragment. So FragmentB which implement the interface but will not receive any update.
You should use getParentFragment to access FragmentB from FragmentA, then cast it to the Listener interface.

Android - Talk to an active Fragment from Main Activity

I have a Main Activity with a bunch of Fragments connected to it.
One of the fragments has to be able to recieve data from MainActivity after it has been loaded in the FragmentTransaction and committed.
What is the best way to call a method in that specific fragment?
Do I have to implement a Interface and include it in the MainActivty just for this one fragment? Is there a better way? Can someone point me in the correct direction?
What I have tried now : (Failing at settings ContactsInterface in the MainActivity)
ContactsInterface
public interface ContactsInterface {
void notifyDenied();
void notifyGranted();
}
Fragment
Class.... implements ContactsInterface...
#Override
public void notifyDenied() {
Log.d("DENIED", "DENIED CALLBACK");
}
#Override
public void notifyGranted() {
Log.d("GRANTED", "GRANTED CALLBACK");
}
Main Activity
try {
contactsInterface = (ContactsInterface) this.getApplicationContext();
} catch (ClassCastException e) {
throw new ClassCastException(this.toString()
+ " Needs to implement the methods");
}
Last example throws an ClassCastException.
You need to cast the fragment itself not the Application Context.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
ContactsInterface contactsInterface = (ContactsInterface) fragment;
//contactsInterface.notifyGranted();
//contactsInterface.notifyDenied();
You can get all the active fragments in the FragmentManager and filter for the ones that have the required interface:
supportFragmentManager.fragments
.map { it as? ContactsInterface }
.filterNotNull()
.forEach {
it.notifyDenied()
}
or if you need to use Java:
List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(fragment : fragments) {
if(fragment instanceof ContactsInterface) {
((ContactsInterface)fragment).notifyDenied();
}
}
You may want to also fail (hard or soft) if no fragments are found.
The advantage of doing this is that you don't care how the fragment was started (manually or by layout) and also don't have to care about reconnecting when the activity restarts for example.
This library may be useful to you.
You should do something like this in your fragment:
#Override
public void onCreateView() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onDestroyView() {
super.onStop();
EventBus.getDefault().unregister(this);
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
MessageEvent is just an example, you can use whatever structure you want.
in the Activity you post messages like this:
EventBus.getDefault().post(new MessageEvent());
Check the documentation of the library to have a better idea and use a better approach to your case.
you can use onCreate() and onDestroy() instead. That depends on your logic and you you are updating the view of the fragment when you receive new messages from the Activity.
Happy coding :).

Android nested fragment-fragment interactions

Android best practices for fragment-fragment interaction (described here and here) forces the Activity to implement a listener defined by the child fragment. The Activity then manages the communication between fragments.
From my understanding this is to keep the fragments loosely coupled from each other. However,
Is this also the case for nested fragments? I can imagine it might make sense for a nested fragment to report directly to it's parent fragment instead of the Activity.
If a nested fragment has its parent fragment implement it's listener, how would one (or should one) require the parent fragment to do this. In other words, is a similar to the paradigm to the following but for Fragments:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
If anyone wanted an example of an implementation that ensures parent context implements the callbacks while not caring whether it is an activity or fragment, the following worked for me:
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof Callbacks) {
mCallbacks = (Callbacks) context;
} else {
if (getParentFragment() != null && getParentFragment() instanceof Callbacks) {
mCallbacks = (Callbacks) getParentFragment();
} else {
throw new RuntimeException(context.toString()
+ " must implement " + TAG + ".Callbacks");
}
}
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
Enjoy!
As long as you define an interface in the fragment, you can have the parent activity or parent fragment implementing it. There is no rule that says fragment should not implement interface of a child fragment. One example where this make sense is that fragment A has two children Fragments B, C. A implements B's interface, when A gets a call back, it might need to update fragment C. Exactly the same thing with activity, just different level.
You can implement the same pattern for child/parent interactions using getParentFragment(). The parent fragment refers to whichever fragment has this one added through its ChildFragmentManager. If this Fragment is attached directly to an Activity, this method returns null.

Pattern for Activity / Fragment in android

I've a activity which basically is :
public class FragmentContainer extends FragmentActivityBase implements IRefreshListener {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent().getExtras() == null
|| getIntent().getExtras().get("type") == null) {
showProductList();
}
else
{
if (getIntent().getExtras().get("type").equals("customer"))
showCustomerList();
}
#Override
public void showProductList() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
// load the product list
ProductList fragment = new ProductList();
fragmentTransaction.replace(R.id.fragment_container, fragment)
.addToBackStack(null);
fragmentTransaction.commit();
}
.....
}
in the fragment, I use onCreateView to get intent and then I create my view.
If I need to change the fragment, I get the reference to the parent Activity (taken from onAttach) and I call method referenced by the IRefreshListener.
like :
IRefreshListener mCallback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (IRefreshListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement IRefreshListener");
}
}
public void callCustomer() {
mCallback.showCustomerList();
}
It works but whne I change the orientation, even I use setRetainInstance(true) it will be reseted.
I have 2 questions :
Do I use the good pattern to manage my application. The big activity which contains one fragment become bigger with the time
How should I handle orientation change ?
Regards
I do not find this pattern is more perfect or best one, although it is or was a suggestion from Google. Because it could be a worse coding style if fragment knows particular activity or listeners, you might write more and more code, when you wanna to let your fragment know more its "container" or "parents". Will the fragment later be used for other activity which has not been implemented with IRefreshListener etc, you will code much more.
My introduce is using Otto-Bus or Event-Bus. You can just send message from one to one. Every one doesn't have to know each other.

Categories

Resources