Updating Parent Fragment from Child Fragment - android

In my android application, I have two Fragments. Parent Fragment contains list of available Filter Types and when a particular Filter Type is clicked (in Parent Fragment - Yellow Background) corresponding Child Fragment (Pink Background) opens with list of available options for selected filter type. My requirement is once User select/deselect an option in child fragment, it should reflect/update option count (Green color) in parent Fragment.
Please check attached wireframe.

You can use Otto Bus for comunications between Fragments, fragments-activities, services, etc.
Maybe, the first time you can be a little weird if you have not used before but it is very powerful and very easy to use. You can find the library and a tutorial here:
http://square.github.io/otto/
An example. In your adapter or where you have your item click event you cand send a Object by the Bus.
In your bus you invoque the post method and pass the object. (I recommended create a singleton for Bus).
The singleton Bus Provider.
/**
* Canal de comunicacion
*/
public class BusProvider {
private static final Bus REST_BUS = new Bus(ThreadEnforcer.ANY);
private static final Bus UI_BUS = new Bus();
private BusProvider() {};
public static Bus getRestBusInstance() {
return REST_BUS;
}
public static Bus getUIBusInstance () {
return UI_BUS;
}
}
You send a Object in the bus (in your child fragment) like this:
BusProvider.getUIBusInstance().post(itemSelected);
And in your parent fragment you subscribe for this event:
#Subscribe
public void activitySelected(final Item itemSelected) {
}
Hope it helps you!!

Even though my answer might be late, I guess it still could help :
The solution is simple, in case you need to access a parent fragment from a child one, then use a specific tag for the parent when adding it to the stack, like in the following code example :
1) In the containing activity :
// We instanciate the parent fragment
ParentFragment parentFragment = new ParentFragment();
FragmentTransaction ft = fm.beginTransaction();
// We add the parent fragment with a tag, so we can use it later to fetch
// the current instance of the parent fragment from the child fragment
ft.replace(R.id.content_frame, parentFragment, "parent_fragment_tag");
ft.addToBackStack(null);
// Commit transaction
ft.commit();
2) In the child fragment, we get the current parent fragment instance like this :
Fragment parentFragment = getFragmentManager().findFragmentByTag("parent_fragment_tag");
I hope this answer can be of help.

Related

Proper Replacement of Fragments

I have one Activity Called A. The activity has 1 Frame Layout in which Fragments are used. I have two Fragments, Fragment1 and Fragment2. When the Activity is launched, Fragment 1 fills the Frame Layout.
Fragment1 also contains a button that when clicked replaces it with Fragment2 within that same Frame Layout. My question is this, when I click that Button in Fragment1 should I implement that code so that
A) Activity A gets notified of the onClick in the Fragment through an interface using some type of Boolean value and then proceeds to replace it with Fragment2.
OR
B)Implement the code that replaces Fragment1 with Fragment2 within Fragment1 itself For example:
private FragmentTransaction ft;
private Button registerButton, resetButton;
private Fragment fragment;
public LoginFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_login, container, false);
registerButton = (Button)view.findViewById(R.id.register_button);
resetButton = (Button) view.findViewById(R.id.reset_button);
registerButton.setOnClickListener(this);
resetButton.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.register_button: {
fragment = new RegisterFragment();
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
break;
}
}
}
Could someone explain why one over the other? Thanks so much!
Generally, what I do is use an interface of some sort that lives in the fragment being replaced (in this case Fragment 1). Your parent activity then would implement this interface, and thus building a contract between the activities that are the parent of that particular fragment.
When you press your button (or whatever event happens to signal replace), you grab your activity casting it to that interface, and call the particular method.
e.g. Signaling event within the fragment
( (MyFragmentListener) getActivity()).onActionHappens();
Where MyFragmentListener is the inner class of your Fragment and onActionHappens() is the method that sends the signal. This effectively creates a contract between your fragment and any Activity that hosts the fragment. When your action happens, you let the activity know and the activity then overrides the appropriate method to handle the event.
There are other ways to do this, but at the simplest level this is how it can be done.
Why not option B
Option B creates a tight coupling between fragments, which you don't necessarily want. In practice you want the coupling to be between the fragment, and it's host (or parent) which is the Activity. Also, there could be many activities that use that fragment so you abstract away details about the particular activity that uses it by just calling getActivity(). In this case, coupling the fragment and the Activity is acceptable, since of course the two are coupled anyways. We know this because a fragment cannot live without an associated Activity, so it is okay to take advantage of the that tight coupling.
Summary
Pick option A. It is the cleanest route, and avoids assuming implementation details that you have to do in option B.
It is also the basic solution you have without any external libraries or details required. If you want a more advanced solution, checkout Otto (made by Square) Link to the library here

Android Fragments sharing info ways

i have a internal discussion about what way is better to share info between fragments contents inside a controller activity. In a first classical way, you can set arguments when you are going to replace fragments as follows:
//Just now i'm inside Fragment 1 and i'll navigate to Fragment 2
Fragment newFragment = getFragmentManager().findFragmentByTag(Fragment2.TAG);
Bundle b = new Bundle();
b.putBoolean("test1", true);
// Create new fragment and transaction
if(newFragment==null)
newFragment = Fragment2.newInstance(b);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)//.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim)
.replace(R.id.fragment_place, newFragment, Fragment2.class.getName())
.addToBackStack(newFragment.getClass().getName())
.commit();
The newInstace method does as i meant above, so, with setArguments:
public static Fragment2 newInstance(Bundle arguments){
Fragment2 f = new Fragment2();
if(arguments != null){
f.setArguments(arguments);
}
return f;
}
But Fragment1 and Fragment2 they are both inside a ControllerActivity, so i can also think about a second way to share information obtained in Fragment1 towards Fragment2, through declaring attributes in the ControllerActivity, so i could do (declaring previously an object in the activity) as follows inside any fragment:
EDIT
public class ControllerActivity extends FragmentActivity{
int value = 5;
...
And then, inside my fragment:
((SplashActivity)getActivity()).value = 10; //i can assign or recover value when i desire
My question is what inconveniences would have doing as the second way.
Writing code using 2nd way is fast. But the problem is you have to cast the general Activity to the more specific SplashActivity in which the value variable exists. If you want to use the Fragment with another Activity, or you want a Fragment to be a general purpose UI component you have to use interface for passing the data.
As mentioned in comments, bellow links provide more details about interface/callback method:
android docs
video from slidenerd
Hope this answers your question.

Unable to access layout inflater as child view has not initialised

I have an Android activity that searches a web service for new content to display then either displays a NoResultFragment or a ResultFragment which represents a swipe stack for the user to swipe through the items returned. Because I need to manage the stack, retrieving more data in the background as the stack gets low etc from the Activity, all of the stack details are held at the activity level and the yes/no actions trigger methods on the activity. All good so far.
The problem is I am using the layout inflater in the ResultFragment class to generate dynamic child Views, each one of which represents an item on the stack. These then get returned to the Activity controller which manages them, sends them to the fragment to display, hides them, moves them around etc, so I need access to the child item Views from the activity to do all this. I need to generate the actual child views from within the ResultFragment though, as that is where they will be visually displayed.
I create the ResultFragment, set it to the content area and then try and generate the child views by calling into the fragment created. The error is that the onViewCreate() method has not yet been called on the ResultFragment class as it has only just been added to the content frame, so there is no layoutinflater and my method to return the child View fails. I get the feeling there is something off with my design here, can someone shed some light on how to do this? Is it as simple as just passing through the parent layoutinflater from the Activity class?
Child view creation method
public View getChildView(StorySeed seed, int seedIndex)
{
final View m_view = inflater.inflate(R.layout.fragment_item, null); // Code to populate the view
return m_view;
}
activity method
private void initialiseResults(ArrayList<StorySeed> storySeeds) {
resultsFragment = new ResultsFragment(storySeeds, getApplicationContext());
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, resultsFragment)
.commit();
// load the first results to screen
seedIndex = 1;
for (int i = 0; i < seedsToDisplay; i++) {
getNextToStack();
}
}
It is the call to getNextToStack() that is going into the Fragment class and calling the getChildView() method
I would suggest that you create the views in the activity (the controller) and pass them to the fragment as needed. The fragment is your MVC "view" and it should only tell the controller what happened. The controller decides what to do after that.
The way you can have one fragment replace itself by another is to call a method on the activity. Here's a quick example:
interface IAppController {
void onResultsNotFound();
}
class MyActivity extends Activity implements IAppController{
....
public void onResultNotFound(){
//switch fragments
}
}
class MyFragment {
....
void myMethod(){
IAppController controller = (IAppController) getActivity();
controller.onResultsNotFound();
}
}
Hope this helps

Android navigating to parent Fragment Activity from within Fragments

The main fragment activity in my application has the following function
private final void insertFragmentIntoView(final SherlockFragment fragment,
String tag) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_content, fragment, tag);
ft.commit();
}
The R.id.fragment_content is a frame layout and i basically insert a new fragment into this frame. Now the frame that i insert has a button that should take me onto a new screen. What i want is that all navaigation in my application should take place in my FragmentActivity. How can i call my FragmentActivity from with a child fragment ?
Kind Regards
Make a listener class in your fragment and your parent activity will implement that listener .
Now register listener in your fragment and call method in which you want to perform some action.
More you can see this link http://developer.android.com/training/basics/fragments/communicating.html
Example how fragment and activity communicate.
class MyFragment extends Fragment{
class interface MyFragmentListener {
doSomeAction();
}
MyFragmentListener myListener;
onAttach(){
myListener=(MainActivity )getActivity();
}
onButtonClick(){
myListener.doSomeAction();
}
}
class MainActivity extends FragmentActivity implements MyFragment.MyFragmentListener
{
doSomeAction(){
//TODO perform some action from your fragment to activity
}
}
Using listeners is the recommended way of communicating between Fragment and your activity.
See this Android documentation section for infromation. Long story short they just implement a listener interface by the Activity class and cast getActivity() result in a fragment to a listener.
From my personal experience this is very convenient because lets you to:
Easilly switch underlying activity (e.g. you host entire fragment in a wrapper activity for compatibility in pre-3.0 and host this fragment along with others in 11+)
Easilly control if the wrapper activity supports callbacks or not. Just check is it does implement the listener and do your app specific actions if it doesn't.

How can I avoid code duplication with Fragment callbacks to a details activity?

I'm using a master/detail pattern with one activity managing the 2-pane view and the selector list and the other activity managing the detail fragments. I'm using an interface to handle fragment callbacks to the Activities.
There seems to be a lot of code duplication though with the details activity copying many of the callback methods from the 2-pane activity. Where appropriate, I've used static methods where context isn't required, but where context is required I'm not sure how to remove the code duplication neatly.
Inheritance with an Abstract parent Activity is an option but seems like a lot of overhead.
Is there a better way of doing this?
I asked a similar question here: How many Activities vs Fragments?
I too was worried about the duplication of logic, and the answers I got caused quite a healthy debate.
In the end I chose to follow Stephen's answer, of putting as much of the logic into the Fragments themselves.
However other contributors seemed very keen on duplicating the logic as per the examples.
So lets say u have Activity AB that controls Frag A and Fragment B.
MY ANSWER:
If the variable is used by Frag A and Frag B, put it in Activity AB. Then pass it to Frag A or Frag B everything they need it. Or have Frag A or Frag B retrieve it from Activity AB.
If the variable is used by Frag A only or Frag B only, put it in Frag A or Frag B respectively.
For methods that are used by both Frag A and Frag B, put those methods in another class and create instances of that class inside Frag A and Frag B for each of the 2 fragments to use.
The following is an answer I gave to another person. However, it seems relevant to your question so I am re-posting it here.
Inside Fragment A u need an interface that Activity AB can implement.
In the sample android code, they have:
private Callbacks mCallbacks = sDummyCallbacks;
/*A callback interface that all activities containing this fragment must implement. This mechanism allows activities to be notified of item selections.
*/
public interface Callbacks {
/*Callback for when an item has been selected. */
public void onItemSelected(String id);
}
/*A dummy implementation of the {#link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity. */
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
The Callback interface is put inside one of your Fragments (let’s say Fragment A). I think the purpose of this Callbacks interface is like a nested class inside Frag A which any Activity can implement. So if Fragment A was a TV, the CallBacks is the TV Remote (interface) that allows Fragment A to be used by Activity AB. I may be wrong about the details because I'm a noob but I did get my program to work perfectly on all screen sizes and this is what I used.
So inside Fragment A, we have:
(I took this from Android’s Sample programs)
#Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
//mCallbacks.onItemSelected( PUT YOUR SHIT HERE. int, String, etc.);
//mCallbacks.onItemSelected (Object);
}
And inside Activity AB we override the onItemSelected method:
public class AB extends FragmentActivity implements ItemListFragment.Callbacks {
//...
#Override
//public void onItemSelected (CATCH YOUR SHIT HERE) {
//public void onItemSelected (Object obj) {
public void onItemSelected(String id) {
//Pass Data to Fragment B. For example:
Bundle arguments = new Bundle();
arguments.putString(“FragmentB_package”, id);
FragmentB fragment = new FragmentB();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().replace(R.id.item_detail_container, fragment).commit();
}
So inside Activity AB, you basically throwing everything into a Bundle and passing it to B. If u are not sure how to use a Bundle, look the class up.
I am basically going by the sample code that Android provided. The one with the DummyContent stuff. When u make a new Android Application Package, it's the one titled MasterDetailFlow.

Categories

Resources