Android pass argument from fragment to previous fragment? - android

Need your help to figure out what is the best approach to achieve the following:
Activity -> Fragment A -> Fragment B.
When a user is on fragment B, and he clicks save. I want it to Remove/popBackStack Fragment B and return to Fragment A with the data passed from Fragment B.
Thanks in advance!

you could define interface and attribute in Fragment B,such as:
public interface OnSelectedListener {
void onSelected(String s);
}
private OnSelectedListener mOnSelectedListener;
public void setOnSelectedListener(OnSelectedListener onSelectedListener) {
mOnSelectedListener = onSelectedListener;
}
when Fragment A -> Fragment B:
new OnSelectedListener();
when click save in Fragment B
onSelectedListener.onSelected("");
other method : DataBase, SharedPreferencesHelper

Try to use
LocalBroadcastManager
Web Reference with Example -
https://gist.github.com/Antarix/8131277

The quickest solution would be to save the desired values in onPause or onStop of your fragment-B using any preferred storage method (like SharedPreferences or SQLite) and load them back in the onResume or onStart of fragment-A.
or replace the save part by introducing a stub method in your Activity which takes the Bundle of values and pass-on to the other fragment.

Related

Android Studio: Moving between fragments and actions inside fragments

My project operates around a navigation activity that uses fragments for the individual menu pages. I'd like to be able to open other fragments through clicking a button (as opposed to a navigation menu icon), however I can't figure out how to accomplish this. I've looked at both the following resources (and more), but I don't fully understand them.
How can I make my button to do something in Fragments,ViewPager
https://developer.android.com/training/basics/fragments/communicating.html
Furthermore, clicking a button would also have to call on code in the main activity that uses the app bar.
If someone can explain to me how to accomplish the desired effect, that would be great.
If you want to open a fragment by pressing a button from a fragment the call should go through the current activity.
Create a callback to the activity and call that callback when pressing the button. Then the Activity launches the second fragment when the callback is called.
This way the first fragment does not need to know anything about the second fragment. The Activity deals with the navigation between fragments in the same activity.
I think this is the cleanest and easiest solution.
edit: I'm basically saying the same as the link to the android documentation posted in the question. I think this is the best solution.
For simplicity: Activity = [A], Fragment 1 = [B], and Fragment 2 = [C]
Step 1: Create an interface inside [B] called IOnInitiate[C]Listener, and within that interface create a method called void Initiate[C]();.
Step 2: Create a private property within [B] of type IOnInitiate[C]Listener called (your-prefix-convention)OnInitiate[C]Listener.
Step 3: Create a public method within [B] called public void SetInitiate[C]Listener(Activity activity), and cast the activity parameter into the private property created in step 2.
Step 4: [A] must implement the interface [B].IOnInitiate[C]Listener and the method public void Initiate[C]().
Step 5: From [A], whenever you create a new instance of [B], be sure to call the method from step 3 and pass in this for the Activity parameter. Otherwise a null exception will occur.
Step 6: Now whenever you need to initiate [C] from [B] simply call the interface method from [B]'s private property. Example:(prefix)OnInitiate[C]Listener.Initiate[C]();
This is what mine looks like. I use C# for my development, so your syntax may be different.
public class A : Activity, B.IOnInitiateCListener
{
private void InitiateB()
{
B b = new B();
b.SetInitiateCListener(this);
b.Show(FragmentManager, "B");
}
public void InitiateC()
{
C c = new C();
c.Show(FragmentManager, "C");
}
}
public class B : Fragment
{
public interface IOnInitiateCListener
{
void InitiateC();
}
private IOnInitiateCListener _IOnInitiateCListener;
public void SetInitiateCListener(Activity activity)
{
_IOnInitiateCListener = (IOnInitiateCListener)activity;
}
private void InitiateC()
{
_IOnInitiateCListener.InitiateC();
}
}

Fragment transactions and activity transitions

I have this scenario in my app:
One activity(A) with multiple fragments calling another activity(B) at some point.
Flow for that goes like this: F1 => F2 => F3 => B or F1 => F2 => B where F(n) represents fragment.After I finish activity B it returns me to F3 or F2 but my goal is to show user F1 so I tried sending event via event bus and replacing any other fragment with F1,note that I'm adding every fragment to backstack.So I succeed with it but if I call fragment F2 or F3 application crashes also sometimes I get "IllegalStateException: Can not perform this action after onSaveInstanceState".
So after trying a lot of approaches I simply did this :
public void onClick(View v){
//started activity B
//replaced current fragment with F1
}
The end result of this was seeing F1 before activity B ,and everything else worked fine without crashing.So to solve that glitch I replaced fragment 100 ms after activity B is started.
public void onClick(View v){
//started activity B
new Handler().(new Runable(){
#Override
public void run()
{
//replaced current fragment with F1
}
},100);
}
But I feel this is ugly way to solve this problem and I want to ask you if there is better solution?
EDIT:
I was inspired by spcial answer so I did similar thing with states.
In activity A I have two variables.
boolean wasAnotherActivityCalled=false;
String showFragment=null;
In my fragment I have this :
public void onClick(View v){
//started activity B
getActivity().wasAnotherActivityCalled=true;
getActivity().showFragment=FragmentOne.class.getSimpleName();
}
in activity A I have this :
#Override
protected void onResumeFragments() {
super.onResumeFragments();
if(wasAnotherActivityCalled)
{
if(showFragment.equals(F1.class.getSimpleName()))
{ //do your logic here}
wasAnotherActivityCalled=false;
showFragment=null;
}
}
I have something similiar in my App. What I did was to use a simple "state-machine" where I have an int attribute which represents the current state (0 = Fragment1, 1 = Fragment2...etc) and an ArrayList with all fragments which I need. If I have to switch the fragment I also increment the state and just load the fragment from the ArrayList.
In my onPause() method I save the state in sharedPreferences() and in the onResume() method I load the state from sharedPreferences() and do a initFragment(state) where I just replace the fragmentLayout with the fragment from fragmentArray[state] :-)
With this behaviour I could handle backstack on my own, can go back and furth and save the state of the current needed fragment everytime the user changes the activity and comes back. Furthermore I don't commit the fragments into backstack because it is already handled through myself.
I hope I could help you with this.
Dont add your fragment into backstack while commiting it

Android: Do I have to send all the variables to retain the values before fragment transaction?

Suppose I have 2 fragments A and B. A has 2 integer variables named data_1=2 and data_2=3. I do a transaction from Fragment A -> Fragment B. Note that Fragment B needs only data_1 but it doesn't need data_2, so, I send only the variable data_1 through Bundle. So, when I do another transaction from Fragment B -> Fragment A, sending back the modified value of data_1, I will use the new value of data_1 but will the original value of data_2 = 3 be retained ?
If not, then how do I retain this value?
There are various ways of doing it, but the easiest way in my Opinion would be to share data with the parent activity.
Basically like so:
class MainActivity extends Activity {
public static int data_1 = 1, data_2 = 2;
//All your other code goes here
}
Then in your child fragment to set the data you would go:
MainActivity.data_1 = 5;
Whereas to read the data you just call the static value.
int current_data = MainActivity.data_1;
If you need instances of the activity for whatever reason you can set up getter and setter functions for an instance's
(not static) variable.
you can also use onSavedInstanceState(Bundle outstate) callback method of fragment and set your value in the bundle. So when you come back to previous fragment, you will get the retain value from the bundle of the onCreate(Bundle savedInstanceState) callback method.

How to save custom Objects onSaveInstanceState without implementing parcelable

i need to save a custom object that i use in a fragment so it will not be lost when the screen rotates (when the app calls onDestroy and then recalls onCreate)
now the normal way to do so is to implement Parcelable interface and save it to the bundle as a Parcelable object.
that is a very tedious way of doing things.
is there a way to just pass the object along as "putObject" method?
You can save your data in fragment, retained during a configuration change like in example.
Extend the Fragment class and declare references to your stateful
objects.
public class RetainedFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
.. getter and setter
}
Then use FragmentManager to add the fragment to the activity.
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
..
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (RetainedFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
} else {
// available dataFragment.getData()
..
// save data in onDestroy dataFragment.setData(yourData);
The best way is to implement Parcelable (Faster).
Easier (not efficient) way is to implement Serializable and add the object into the bundle as serializable.
well searching i found no official way of doing so, so here are two "hacks" i found around the problem:
1)create a class that extends Application class, in it add an arrayList of objects.
inside onSaveInstanceState call:
getApplication().getObjectArray().add(YourObject);
save the Object index inside the bundle using putInt.
extract it inside the method onReturnestoreInstanceState.
2)my less favorite one:
android automatically saves the states of its views
therefor a way to save an object will be to create a view set its visibility to none so it wont show on the screen and then add each object we want to the view using the methods:
view.setTag(key,Object); or view.setTag(Object);
now inside onReturnestoreInstanceState get the view and extract the tags.
unfortunately i couldn't find a more simple way of saving an object
hope this one helps you out (in my app i ended up using the first method)

Finishing current activity from a fragment

I have a fragment in an activity that I am using as a navigation drawer. It contains buttons that when clicked start new activities (startActivity from a fragment simply calls startActivity on the current activity).
For the life of me I can't seem to figure out how I would finish the current activity after starting a new one.
I am looking to achieve something like this in the fragment:
#Override
public void onClick(View view) {
// TODO Auto-generated method stub
if (view == mButtonShows) {
Intent intent = new Intent(view.getContext(), MyNewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
}
But it seems Fragment.class does not implement finish() (like it implements startActivity(...)).
I would like the activity backstack cleared when they launch the 2nd activity. (so pressing back from the new activity would technically drop them back to the launcher)
When working with fragments, instead of using this or refering to the context, always use getActivity(). You should call
Java
getActivity().finish();
Kotlin
activity.finish()
to finish your activity from fragment.
Well actually...
I wouldn't have the Fragment try to finish the Activity. That places too much authority on the Fragment in my opinion. Instead, I would use the guide here: http://developer.android.com/training/basics/fragments/communicating.html
Have the Fragment define an interface which the Activity must implement. Make a call up to the Activity, then let the Activity decide what to do with the information. If the activity wishes to finish itself, then it can.
As mentioned by Jon F Hancock, this is how a fragment can 'close' the activity by suggesting the activity to close. This makes the fragment portable as is the reason for them. If you use it in a different activity, you might not want to close the activity.
Code below is a snippet from an activity and fragment which has a save and cancel button.
PlayerActivity
public class PlayerActivity extends Activity
implements PlayerInfo.PlayerAddListener {
public void onPlayerCancel() {
// Decide if its suitable to close the activity,
//e.g. is an edit being done in one of the other fragments?
finish();
}
}
PlayerInfoFragment, which contains an interface which the calling activity needs to implement.
public class PlayerInfoFragment extends Fragment {
private PlayerAddListener callback; // implemented in the Activity
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback= (PlayerAddListener) activity;
}
public interface PlayerAddListener {
public void onPlayerSave(Player p); // not shown in impl above
public void onPlayerCancel();
}
public void btnCancel(View v) {
callback.onPlayerCancel(); // the activity's implementation
}
}
You should use getActivity() method in order to finish the activity from the fragment.
getActivity().finish();
This does not need assertion, Latest update in fragment in android JetPack
requireActivity().finish();
In Fragment use getActivity.finishAffinity()
getActivity().finishAffinity();
It will remove all the fragment which pushed by the current activity from the Stack with the Activity too...
Every time I use finish to close the fragment, the entire activity closes. According to the docs, fragments should remain as long as the parent activity remains.
Instead, I found that I can change views back the the parent activity by using this statement:
setContentView(R.layout.activity_main);
This returns me back to the parent activity.
I hope that this helps someone else who may be looking for this.
Very simple...
1- just grab activity by getActivity() in the fragment
2- then call finish();
So just getActivity().finish(); will finish the parent activity.
Try this. There shouldn't be any warning...
Activity thisActivity = getActivity();
if (thisActivity != null) {
startActivity(new Intent(thisActivity, yourActivity.class)); // if needed
thisActivity.finish();
}
You have two options for Java and Kotlin. However, logic of both ways are same. You should call activity after call finish() method.
Answer for Kotlin,
If your activity cannot be null, use Answer_1. However, if your activity can be null, use Answer_2.
Answer_1: activity!!.finish()
Answer_2: activity?.finish()
Answer for Java,
getActivity().finish();
To finish activity in a Fragment use:
getActivity().finish();
Simple solution:
activity?.finish()
yes Fragment.class does not implement finish()
When working with fragments, instead of using this or refering to the context, always use getActivity(). You should call

Categories

Resources