I have this design problem. I have an activity which hosts two fragment and any given point of time only one activity is visible.
Activity A hosts Fragment B and Fragment C
Host Activity A implements FragmentCommunicator interface and implement respond(int code) method using this method communicator both Fragment B and C can talk to host Activity.
Now here is the problem.
In onClick of Host activity I check certain condition and based on that I take decision which fragment to show.
public void onClick(View v) {
switch (v.getId()) {
case R.id.some_button
if(authNotedone)
showFragmentA();
else{
EDIT: //setting some properties before showing Fragment B
showFragmentB();
}
}
}
So far it works fine. If condition is true FragmentA will be visible with login form. After successful login I would like to show fragment B again. How can I achieve this.
What I have tried?
1) After successful login Fragment A send message to Host activity using Fragmentcommunicator's respond(code) method but it was ugly design as I have to either call performClick() or call showFragmentA() in respond method if code is success.
There could be multiple such conditions in my program How I can handle these neatly?
Use a interface as a call back to the activity. Once you get the message in the activity there is no need to click the button just replace the existing fragment in the container.
Implement the interface in the activity
FragmentB newFragment = new FragmentB();
Bundle args = new Bundle();
args.putInt("key", "message");
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
// replace with fragmentb. no need to perform click again.
// based on the message you decide which fragment you want to replace with
transaction.commit();
You can find an example #
http://developer.android.com/training/basics/fragments/communicating.html
Do you want to navigate between fragments? If so, why don't you implement navigation tabs, have a look at this link.
Related
So I have Activity A with Fragment A.1, and I also have Activity B with Fragment B.1.
What I want to ask is, how do I move directly from Fragment A.1 to Fragment B.1?
I know to move from Fragment A.1 to Activity B, is by:
Intent i = new Intent (getActivity (), MainActivity.class);
startActivity (i);
getActivity ().finish();
But how to move straight to Fragment B.1?
Each Activity A and Activity B has a different <FrameLayout> for Fragment replacement
UPDATE 1.0
I've tried my own way and also the way #cewaphi answered with code like this,
In Activity A:
Intent i = new Intent(TransactionDone.this, MainActivity.class);
i.putExtra("immediatelyTransactionToFragment", true);
startActivity(i);
finishAffinity();
In Activity B:
boolean shouldTransitionToFragment = getIntent().getBooleanExtra("immediatelyTransationToFragment", true);
if (shouldTransitionToFragment) {
Fragment fragment = new Wallet();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.mainFrameLayout, fragment);
transaction.commit();
Log.d("DEBUGGING REDIRECT", "Go to Fragment B.1");
}
The log "Go to Fragment B.1" was created but the transaction doesn't work
When using a single activity and e.g. using the navigation component is not an option.
Consider the following:
In your fragment A.1 when starting the activity store a Boolean
i.putExtra("immediatelyTransationToFragment", true);
In activity B
shouldTransitionToFragment = getIntent().getBooleanExtra("immediatelyTransationToFragment");
// after activity was created
if (shouldTransitionToFragment) {
// Execute the transition action as you would when pressing the button
}
Update 2020/09/07
You are trying to transition to a Fragment from your Activity like this:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.mainFrameLayout, fragment);
transaction.commit();
The documentation states that you should first add the fragment to the activity:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
Apparently your transition works when you click your button. Are you doing it the same?
But I assume at that time the activity has already been created.
Try once to add your fragment instead of replace. I don't know how your container is initialised but adding might be the operation you want, I refer to this good answer for clarification.
Also consider to perform to call this transaction after your activity was created.
I have one activity containing one container that will receive 2 fragments.
Once the activity initialises i start the first fragment with:
showFragment(new FragmentA());
private void showFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment, fragment.getTag())
.addToBackStack(fragment.getTag())
.commit();
}
Then when the user clicks on FragmentA, I receive this click on Activity level and I call:
showFragment(new FragmentB());
Now when I press back button it returns to fragment A (thats correct) and when i press again back button it show empty screen (but stays in the same activity). I would like it to just close the app (since the activity has no parent).
There are a lot of posts related with Fragments and backstack, but i can't find a simple solution for this. I would like to avoid the case where I have to check if im doing back press on Fragment A or Fragment B, since i might extend the number of Fragments and I will need to maintain that method.
You are getting blank screen because when you add first fragment you are calling addToBackStack() due to which you are adding a blank screen unknowingly!
now what you can do is call the following method in onBackPressed() and your problem will be solved
public void moveBack()
{
//FM=fragment manager
if (FM != null && FM.getBackStackEntryCount() > 1)
{
FM.popBackStack();
}else {
finish();
}
}
DO NOT CALL SUPER IN ONBACKPRESSED();
just call the above method!
addToBackStack(fragment.getTag())
use it for fragment B only, not for fragment A
I think your fragment A is not popped out correctly, try to use add fragment rather replace to have proper back navigation, however You can check count of back stack using:
FragmentManager fragmentManager = getSupportFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
and you can also directly call finish() in activity onBackPressed() when you want your activity to close on certain fragment count.
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
I want to send an intent from one activity to a specific fragment like this picture, and fragment is in the fragmentactivity (fragmentactivity includes five fragments). I don't have any idea to implement it.
I don't exactly know what do you mean by "to intent from activity to specific fragment". So I just assume you want to show/navigate to your fragment in your activity. Here's the simple code:
//show your fragment inside your activity
YourFragment fragment = new YourFragment();
getIntent().putExtra("KEY", "Value"); //pass data to your fragment
transaction = this.getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.IDofYourLayoutToBeReplaced, fragment);
transaction.commit();
//in your fragment, retrieve the data
String yourVariable = getActivity().getIntent().getExtras().getString("KEY");
or to better understand, you can check this link
I have this issue in Android. Consider three Fragments: A, B, C. C can be called from A or from B. Is there anyway to know from which fragment, C was called?
Edited
Ok guys I'm going to explain what I'm trying to do. Suppose I have this call: A calls B, B calls C.
When I press the back button in C It gets me to B, thats fine. But when I press the back button again, it takes me to C, instead of A.
This is my code:
#Override
public void onBackPressed() {
//this is the current fragment
Fragment fragmentActual = this.getSupportFragmentManager().findFragmentById(android.R.id.tabcontent);
String fragmentTag = fragmentoActual.getTag().toString();
//If I press the back button in C:
if(fragmentTag.equals("TAG C")){
Fragment removefragment = this.getSupportFragmentManager().findFragmentByTag("TAG B");
Fragment fragmentClient = this.getSupportFragmentManager().findFragmentByTag("TAG C");
//If Im NOT passing arguments to B, I know this is a new form
if(removefragment.getArguments()== null){
//I always pass arguments to fragment C, but just in case:
if(fragmentClient.getArguments()!= null){
Bundle mArguments = fragmentClient.getArguments();
//FRAGMENT B
FragmentB fragmentB = new FragmentB ();
fragment.setArguments(mArguments);
FragmentManager manager = this.getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.addToBackStack(null);
ft.replace(android.R.id.tabcontent,fragmentB,"TAG B");
ft.commit();
}
}else{
super.onBackPressed();
}
}else{
super.onBackPressed();
}
}
Now I'm going to explain the code. Basically what it does is to replace fragment B, when fragment C is called. I do this, because I need to pass arguments to fragment B. But when I do the replacement, the "history" of the fragment B is lost, I mean when I press back button in B, I cant go back to fragment A (HERE IS WHY I WANTED TO KNOW IF I CAN KNOW WHO CALLS WHOM).
The firts time when I call fragment B, I dont pass arguments because is a blank form. But when I call to C, staying in B, I need to pass arguments to fragment B (when back button is pressed), so It can shows updated information.
Please if there something that is not clear, let me know so I can explain myself better.
Edited 2: This issue has something with this https://stackoverflow.com/questions/16703604/back-press-button-when-i-save-a-form-for-the-first-time-a-list-view-is-not-updat. Maybe it does my idea more clear.
The answer of Luksprog I think is the best: "You may want to tackle those issues. You always have the option of passing a Bundle with data to the newly created fragment mentioning who called it. Then using getArgument() in the fragment will know who called it.".
I haven't found another better way.
You can use the setTargetFragment method to set which was the parent fragment. Then you can use the method getTargetFragment to find out who called you.
What you are doing is transitioning between Fragments, call addToBackStack() as part of your FragmentTransaction:
i guess, This is what you need.
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
super.onBackPressed();
}
}
You can use FragmentManager for creating a back stack of your fragments. You also have to work with Fragment Transactions first. Further informations see: http://developer.android.com/guide/components/fragments.html#Transactions