I have an Activity A. Activity A calls fragment frag1. frag1 calls fragment frag2. Lastly frag2 calls frag3.
When I click on a button in frag3, I want to call frag1, pass and parse an object from frag3 to frag1. I tried to do this with an object bundle sent from frag3 to frag1.
I see that there is a popBackStack() method. However, I am a little confused on how this would work. Is it safe to use this method?
I do not know how to do it.
Thanks in advance.
Use Event Bus pattern for passing data(events) between fragments. Then work with you fragment stack in usual way.
There are several popular libraries that implement event bus. I personally prefer
EventBus
Otto
use Local Broadcast for this.
write Broadcast receiver on fragment 1,
On apply button of fragment 3, broadcast your data , and then pop fragment 3
example-
private final BroadcastReceiver myLocalBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
;
Bundle bundle = intent.getExtras();
if (bundle != null) {
get data from bundle
}
};
on fragment 3(apply button):
Intent localBroadcastIntent = new Intent(Constant.MY_ACTION);
Bundle bundle = new Bundle();
bundle.put("your data);
localBroadcastIntent.putExtras(bundle);
LocalBroadcastManager myLocalBroadcastManager = LocalBroadcastManager.getInstance(getActivity());
myLocalBroadcastManager.sendBroadcast(localBroadcastIntent);
getActivity().getSupportFragmentManager().popBackStack();
Related
I have two activities. And I passed the argument to the target activity by intent:
Bundle bundle = new Bundle();
bundle.putString("ImagePath", path);
Intent intent = new Intent(getActivity(), DetailActivity.class);
intent.putExtra("paths", bundle);
startActivity(intent);
The target activity DetailActivity has a fragment, and I want to get the argument ImagePath in it. Now I have two method:
I get the argument in the DetailActivity by getIntent() and then pass it to the fragment using setArgmunets()
I get the argument in the target fragment using getActivity().getIntent() directly.
I like the method 2 and use it now because the clean code. But the Android Studio tell me the message Method invocation 'getIntent' may produce 'java.lang.NullPointerException' in getIntent().
So should I abandon the method 2?
Update: Final, I used the method 1, because of this answer :
From the Fragment documentation:
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.
You can check for extras..
Intent intent = getActivity().getIntent();
if(intent.hasExtra("paths")){
// get the data
}else{
// Do something else
}
Use Below Code :
Bundle bundle = new Bundle();
bundle.putString(Constants.BUNDLE_DATA, "From Activity");
Fragment fragment = new Fragment();
fragment.setArguments(bundle);
and in Fragment onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString(Constants.BUNDLE_DATA);
return inflater.inflate(R.layout.fragment, container, false);
}
If you want to send large data ,then create a model and make that model implements Serializable .
No, it's not about the intent. It's because in some point of the time(e.g. fragment has been detached from the activity) getActivity() method can return null. So, correct call will be the next:
if(getActivity != null) getActivity().getIntent()
getActivity() on Fragment may produce null.
So you need to use either any interface for communication between activity and fragment or use bundle by passing in setArgument() in instance of fragment.
I have a tabbed activity with one of the tab has favorite movie recyclerView List. In another tab, all the movies will be shown and onclick of one movie will open the movie details Activity, where he can favorite that movie. I am only saving favorite movie's id in shared preferences. After he goes back to the favorite tab, I can fetch all the movies and display it, but for every new movie addition, fetching all the favorite items is not a good idea and maintaining the static variables for newly favorite movies and refreshing the list also not looking like a good idea.
I am thinking of using Interfaces,broadcast receiver or RxJava approach for this. But for interfaces, I can't hold the favorite tab instance in movie details activity all the time. Rxjava's Publish subject also good, but I need to maintain static reference to send event from movie details activity.
I am thinking the broadcast receivers or Rxjava approaches are the best way here. Please help me to pick the right implementation.
You can Broadcast Intent from the previous fragment after you get the response in the next fragment make sure only the next fragment/tab is loaded you can also set data in the Activity also so if any change made in the data Fragment can incorporate it and do not override destroyItem this will
help recreate fagment object again and you will get fresh data...problem will arise when
you have to make changes from you next fragment to previous fragment!
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Intent intent = new Intent("key_to_identify_the_broadcast");
Bundle bundle = new Bundle();
bundle.putString("edttext", json.toString());
intent.putExtra("bundle_key_for_intent", bundle);
context.sendBroadcast(intent);
}
and then you can receive the bundle in your fragment by using the BroadcastReceiver class
private final BroadcastReceiver mHandleMessageReceiver = new
BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle =
intent.getExtras().getBundle("bundle_key_for_intent");
if(bundle!=null){
String edttext = bundle.getString("edttext");
}
//you can call any of your methods for using this bundle for your use case
}
};
in onCreateView() of your fragment you need to register the broadcast receiver first otherwise this broadcast receiver will not be triggered
IntentFilter filter = new IntentFilter("key_to_identify_the_broadcast");
getActivity().getApplicationContext().
registerReceiver(mHandleMessageReceiver, filter);
Finally you can unregister the receiver to avoid any exceptions
#Override
public void onDestroy() {
try {
getActivity().getApplicationContext().
unregisterReceiver(mHandleMessageReceiver);
} catch (Exception e) {
Log.e("UnRegister Error", "> " + e.getMessage());
}
super.onDestroy();
}
You can create separate broadcast receivers in all of your fragments and use the same broadcast to broadcast the data to all of your fragments. You can also use different keys for different fragments and then broadcast using particular key for particular fragment.
In your case, you need to specify setOffscreenPageLimit 0, so that when you are on the second page, the first one is destroyed, and vice-versa.
So, every time you tab your listView or recylerView load again.
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(0);
I have 4 Fragments and I am trying to click a button on FragmentA and call a method that changes the visibility of some views on FragmentB and populate it.
I tried an interface, but I can't seem to get it to work between 2 fragments. I can call the interface method from a fragment if I implement it in the activity, but I can't implement it in a fragment and call it in a fragment.
Is there a different way to do this? I don't think I can use the static keyword.
I am suggesting you can use broadcast receiver its, good to perform action anywhere and easy to use.
In your first fragment you can define receiver and from another fragment, you can send broadcast or action.
Example are following.
Write following code in your first fragment in which you want to update view,
private void registerReciver() {
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals("UPDATE_FRAG_A")) {
// here you can fire your action which you want also get data from intent
}
}
};
IntentFilter intentFilter = new IntentFilter("UPDATE_FRAG_A");
getActivity().registerReceiver(broadcastReceiver, intentFilter);
}
And In your second fragment write following code for fire action,
Intent intent=new Intent();
// Here you can also put data on intent
intent.setAction("UPDATE_FRAG_A");
getActivity().sendBroadcast(intent);
Assume that all the fragments are in the same activity.
Define a interface in FragmentA, which is a Listener
Expose what you want to do in FragmentB via a public method
Implement FragmentA's interface in the parent activity by calling the public method of FragmentB
For more inforamtion,see Communicating with Other Fragments
This might have already answered but I am still troubling with a function like this. Let's say I have activity A and activity B. B holds a viewpager with several fragments in it. I would like to call a function in the fragment held by activity B from activity A.
I used callbacks many times to communicate between activites and fragments but every single time it was only the fragment and its holder activity. I do not want to make a static method (the callback listener cannot be static anyway) so it causes a headache for me. The simple static solution to make a static method in the fragment and have it called from the other actually works very well, but I am not sure if it was a good idea as I need to change several things static.
So communicating between Activity B and its fragments is ok, but I cannot call this method in Activity A.
Activity B:
public class ActivityB extends FragmentActivity implements Fragment1.OnWhateverListener
{
...
#Override
public void onWhateverSelected(int position) {
//stuff, here I can call any function in Fragment 1
}
}
The following code snippet is a wrong solution (doesnt even work) but makes a better picture what I would like to do.
Activity A:
ActivityB ab = new ActivityB ();
ab.onWhateverSelected(number);
So how can I do this?
Thank you!
EDIT
Activity A: the method I call
Bundle args = new Bundle();
args.putString("ID", id); // the data to send
Intent frag_args = new Intent(Intent.ACTION_VIEW);
frag_args.setClass(this, MainActivity.class);
frag_args.putExtra("args", args);
startActivity(frag_args);
Activity B:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
...
processIntent(getIntent()); //last line of onCreate, always gets called here
}
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent); // this never gets called here only in OnCreate
}
private void processIntent(Intent intent) {
Bundle args = intent.getBundleExtra("args");
if (args != null) { // check if ActivityB is started to pass data to fragments
String id = args.getString("ID");
Log.i("ID_FROM", "id: " + id); //works well
if (id != null) {
List<Fragment> fragments = new ArrayList<Fragment>();
fragments = getSupportFragmentManager().getFragments();
//NULLPOINTER for the following line
FragmentMainDiscover fr = (FragmentMainDiscover) fragments.get(0);
fr.RefreshHoverView(id);
}
}
}
You are right to stay away from statics. Way too risky, for visual objects that may or may not be on screen.
I would recommend going through activity B, since it is the parent of your target fragment. Create an Intent that starts activity B, and include an intent extra that tells activity B what it should do to the target fragment. Then activity B can make sure that the fragment is showing, and pass the information on to it.
One other idea to pass the info to the fragment is to use setArguments, rather than direct calls. This is a nice approach because Android will restore the arguments automatically if the activity and its fragments are removed from memory.
Does this make sense? Do you want the code?
EDIT
To use arguments, you still need to have activity A go through activity B. This is because activity A doesn't know if activity B, and all its fragments, is running unless it sends it an Intent. But you can include data targeted for the fragments, by putting them inside the intent. Like this:
public class ActivityA extends Activity {
public static final String KEY_FRAG = "frag"; // tells activity which fragment gets the args
public static final String KEY_ARGS = "args";
public static final String KEY_MY_PROPERTY = "myProperty";
public void foo() {
Bundle args = new Bundle();
args.putString(KEY_FRAG, "frag1Tag"); // which fragment gets the data
args.putCharSequence(KEY_MY_PROPERTY, "someValue"); // the data to send
// Send data via an Intent, to make sure ActivityB is running
Intent frag_args = new Intent(Intent.ACTION_VIEW);
frag_args.setClass(this, ActivityB.class);
frag_args.putExtra(KEY_ARGS, args);
startActivity(frag_args);
}
}
public class ActivityB extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//TODO configure activity including fragments
processIntent(getIntent()); // this call is in case ActivityB was not yet running
}
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent); // this call is in case ActivityB was already running
}
private void processIntent(Intent intent) {
Bundle args = intent.getBundleExtra(ActivityA.KEY_ARGS);
if (args != null) { // check if ActivityB is started to pass data to fragments
String fragTag = args.getString(ActivityA.KEY_FRAG);
if (fragTag != null) {
Fragment frag = getSupportFragmentManager().findFragmentByTag(fragTag);
frag.setArguments(args);
//TODO either show the fragment, or call a method on it to let it know it has new arguments
}
}
}
}
public class Fragment1 extends Fragment {
public static final String TAG = "frag1Tag";
#Override
public void onResume() {
super.onResume();
Bundle args = getArguments();
String value = args.getString(ActivityA.KEY_MY_PROPERTY);
...
}
}
This question already has answers here:
Android: Pass data(extras) to a fragment
(3 answers)
Closed 9 years ago.
With Activities, I used to do this:
In Activity 1:
Intent i = new Intent(getApplicationContext(), MyFragmentActivity.class);
i.putExtra("name", items.get(arg2));
i.putExtra("category", Category);
startActivity(i);
In Activity 2:
Item = getIntent().getExtras().getString("name");
How do you do this using Fragments? I am using the compatibility library v4 also.
Does it go in the FragmentActivity? Or the actual Fragment?
And Which Method does it go in? onCreate? onCreateView? another?
And can I see example code please?
EDIT: It is worth noting I am trying to keep Activity 1 as an Activity (or actually ListActivity where I am passing the intent of the listitem when clicked) and then pass to a set of tabbed-fragments (through a Fragment Activity) and I need either tab to be able to get the extras. (I hope this is possible?)
you can still use
String Item = getIntent().getExtras().getString("name");
in the fragment, you just need call getActivity() first:
String Item = getActivity().getIntent().getExtras().getString("name");
This saves you having to write some code.
What I tend to do, and I believe this is what Google intended for developers to do too, is to still get the extras from an Intent in an Activity and then pass any extra data to fragments by instantiating them with arguments.
There's actually an example on the Android dev blog that illustrates this concept, and you'll see this in several of the API demos too. Although this specific example is given for API 3.0+ fragments, the same flow applies when using FragmentActivity and Fragment from the support library.
You first retrieve the intent extras as usual in your activity and pass them on as arguments to the fragment:
public static class DetailsActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// (omitted some other stuff)
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(
android.R.id.content, details).commit();
}
}
}
In stead of directly invoking the constructor, it's probably easier to use a static method that plugs the arguments into the fragment for you. Such a method is often called newInstance in the examples given by Google. There actually is a newInstance method in DetailsFragment, so I'm unsure why it isn't used in the snippet above...
Anyways, all extras provided as argument upon creating the fragment, will be available by calling getArguments(). Since this returns a Bundle, its usage is similar to that of the extras in an Activity.
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
// (other stuff omitted)
}