I have been looking and scouring around the web, even tried to check the official Android doc for "communicating between fragments" or communicating with fragment and activity (http://developer.android.com/training/basics/fragments/communicating.html), and even tried searching a few questions here at StackOverflow just to get a hint to my problem, but none of them seem to answer my case.
I know of the interface listener that is implemented by a host Activity to pass data from Fragment to the host Activity, and used it A LOT in my projects. But I think that model of fragment data passing is actually useful only if there is a "meta" event i.e. onClick, onItemClick, etc) that would fire that custom event.
But for my case, I have a Fragment containing RadioGroup, with the RadioGroup's content, first of which is a view group with several EditTexts, in which I need to send its contents back to the Fragment's host Activity with several other objects. My custom event is being fire by a "meta" event, that is, the RadioGroup.setOnCheckedChangeListener().
To visualize, this is how it is layed out in my layout resource:
RadioGroup
-RadioButton 1
--- LinearLayout (which is toggled to be shown by checking RadioButton 1, hidden when other RadioButton is checked) containing several EditText s
------EditText 1
------EditText 2
------EditText 3
------EditText 4
-RadioButton 2
-RadioButton 3
-RadioButton 4
Every time I check RadioButton 1, it toggles to show the LinearLayout with the EditText, obviously it fires setOnCheckedChangeListener() of the RadioGroup, within which it fires my custom event with parameters like a custom object with contents coming from the EditText s. HOWEVER, my custom event won't be called when I don't check the RadioGroup and when I edit/update the EditText.
I think of using EditText.addTextChangedListener() on those EditTexts and fire my custom event whenever I fill all the data on my form. But I think it's a bit not elegant to do that, and I guess there would be a more elegant and better, if any, way of passing those EditText data from their host fragment back to the Activity, or may be to get the data from Fragment in to the Activity
My question is, how do I pass OR get data FROM fragment to Activity in which I won't depend on "meta" events to fire my custom event or in some other way around.
To communicate back to my activities, I simply add a method which the fragment can call directly. In the Activity class:
public void sendMessage(String message) {
// Do something with the message
}
In the fragment:
((MyActivity)getActivity()).sendMessage("Code Apprentice is the best!");
Related
I have an Activity that contains a ViewPager with four tabs .
each tab has a fragment.
When I click something in tab 4, I want tab 3 to refresh(or access a non-static method in tab 3 ) ..I've searched but all I found had this in it:
FragmentB fragment = (FragmentB)getFragmentManager().findFragmentByTag("FragmentB");
and I can't use it since I never set a tag on the fragment.
I also could call a function from fragment in another fragment but it has to be static , and I don't want that since everything inside it must be static too and that would mess things up for me..
is there a solution to this ?
First of all i think it's not a good practice to update a view which user cannot see on screen at the moment. It's much better to update your data when user navigates to screen. By the way it not our first concern now.
I'm not sure this is still a valid way to find Fragments in a ViewPager byTag but you can find them like below:
This method generates default Tag for a Fragment in ViewPager.
#NonNull
public static String generateViewPagerFragmentTag(int viewPagerId, int position) {
final StringBuilder tagBuilder = new StringBuilder();
tagBuilder.append("android:switcher:");
tagBuilder.append(viewPagerId);
tagBuilder.append(":");
tagBuilder.append(position);
return tagBuilder.toString();
}
Than you can use this tag to find your Fragment with findFragmentByTag method.
Also as mentioned in comments you can use an EventBus library to achieve what you want to do but be careful of Fragment Lifecycle states in ViewPager because the Fragment you want to communicate can be in onPause state an your changes canned be received. This depends on in which lifecycle method you subscribe and unsubscribe to bus. (If you are using OttoBus you can get no subscribers found for this event exception.) You can do same pattern with interfaces. You can create an interface and implement in your Fragments.
For an other solution, you can directly access our fragments in your ViewPager. Here's my answer for another question it.
Finally, as i mentioned at the beginning i think you should implement a solution which updates your data when user switched to specific tab of ViewPager. You can keep your data changes in a mem-cache and listen tab changes and update your view when user exactly navigated to that screen and ready to see data changes. You can check Repository pattern for a more complex solution.
I know this is somewhat of a design question but I do have specific questions for it. I'm trying to understand how to handle a situation like this one:
Let's say I have a RecyclerViewFragment which loads a RecyclerView containing a bunch of Toy objects.
In one situation: Maybe this RecyclerViewFragment is part of a ViewPager on main display. There is a FloatingActionButton add-button present over this RecyclerView. You click the + button and you can add a new Toy to the list. Or you can click a Toy from the list directly and a floating menu pops up with Edit/Delete buttons, and pressing Edit lets you edit the Toy's details in a DialogFragment, or clicking Delete removes it from the RecyclerView.
In another situation: Now I am in a separate part of the app where I want to choose toys to use. So I press a button and a DialogFragment appears with a RecyclerView of Toys. I can click a Toy and it'll be added to my cart.
It seems like I should be re-using the same RecyclerView code in both situations, since they both involve a list of the same Toys. The only difference is that in one situation, I can add Toys and edit Toy details, and in the other situation, there is no Add button and clicking on a toy does something different (adding to a cart as opposed to bringing up an Edit/Delete dialog).
Is this the correct way to handle this:
Communication from Fragment to Activity: Interfaces? Have the RecyclerViewFragment, in the onAttach method, assign a listener of my design to the context. Then when a row of the RecyclerView is pressed, the callback is triggered. Now the underlying Activity can decide what to do with that press -- show the Edit/Delete dialog in one situation, add the Toy to a Cart in the other situation. Either way, the click item sends the Toy to the calling Activity so it can decide what to do with it.
Communication from Activity to Fragment: Now what about the situation with the Add button? This Add button would not be intrinsically part of the RecyclerViewFragment, so when I click Add, it would bring up the details dialog box where I can give the Toy details, and then press OK to add it. So somehow I have to transfer this new Toy to the Fragment to have it added to the RecyclerView. Would I simply do something like this:
RecyclerViewFragment recyclerViewFragment = (RecyclerViewFragment ) getSupportFragmentManager().findFragmentByTag("TOY_RECYCLERVIEW");
recyclerViewFragment.getNewToyAndRefreshList(newToy);
and then in the RecyclerViewFragment:
public void getNewToyAndRefreshList(Toy newToy) {
toyList.add(newToy);
Collections.sort(toyList); //Toy has Comparable implemented, sort by name
recyclerViewAdapter.notifyDataSetChanged();
}
Am I on the right track? Is there a different way to fix this situation?
That's certainly a design question, but IMHO there's a very specific issue on it and I believe it's a good question (reason I'm answering), but that also means other developers might have other approaches to solve the issue.
1. that is a totally fair and acceptable approach to it. You let the fragment be simple UI element and let someone else (the activity) implement the click behavior.
For this approach remember to code it only against the interface. That means, don't cast it to your activity. For example:
// do this
toyClickListener.onToyClicked(toy);
// don't do this
((MyActivity)getActivity()).onToyClicked(toy);
That way you keep the "simple UI element" be completely unaware of who is implementing the behavior.
2. IMO for this kind of scenario (specially on RecyclerView.Adapter) the best thing to do is to forget the UI and only focus on the data. And how speciafically you implement this, will vary on what is your data source.
But the base idea is that you have somewhere a data repo (DB?) and anyone using data from there, should subscribe to changes to it.
So you override RecyclerView.Adapter.registerAdapterDataObserver and unregisterAdapterDataObserver add the subscription/listener code, something like that:
#Override registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
super.registerAdapterDataObserver(observer);
db.subscribe(this, toyList);
}
#Override unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
db.unsubscribe(this);
super.unregisterAdapterDataObserver(observer);
}
#Override public void onDbDataUpdate(new Data comes here){
update the data, and call .notifyDataSetChanged();
}
that way once the FAB + and then dialog is clicked the new Toy gets added to the DB and the adapter gets "automatically" notified.
So if this data comes from a SQLite you can call on the cursor registerContentObserver if it's a RealmDB you'll use addChangeListener, even Android databinding libraries have a ObservableList
How can I get multiple editText value from all fragments by onClick event which located in its container activity? Those EditText are being valid and checking by TextWatcher. I can't get any value of editText by implementing inflate and return fragment's layout to its contain activity.
What is more, how can I handle the situation of passing editTexts' value when all editTexts are valid if using Interface on fragment.
Thanks for any help.
There is several ways
Use SharedPreferences where you save all the value first and
then retrieve it later in activity.
Use interface class as bridge communication between fragment and activity
For Example:example interface class
I currently have the following situation:
1) The "main view" which contains the EditText I'm trying to update. (Let's call it mainView)
2) A fragment that is opened whenever I click in a button that is contained in the "main view", the
fragment receives mainView as parameter.
3) An OnClickListener which is set to a button that is contained by the fragment. This listener receives the fragment as parameter.
Basically what I need to do is, each time I click on the button that triggers the listener, I need to update the editText, however it doesn't seem to be working. I believe it has something to do with "notifying" the view, but I haven't been able to get it working no matter what I try. After I update the text I close the fragment and
Basically the code is the following:
public void onClick(View v){
String newMessageContent = "hello world";
fragment1.mainView.editText1.setText(newMessageContent);
FragmentManager manager = this.fragment1.getActivity().getFragmentManager();
manager.beginTransaction().replace(R.id.container,this.fragment1.mainView.getPlaceHolderFragment()).commit();
}
Please note that I have simplified the problem a little bit and changed the name of the fragment/views in order for you guys to understand better. The text "hello world" is actually dynamic, and depends no another parameter that is received by the OnClickListener.
After I click the fragment does get replaced, so I know the onClickListener is working correctly, however I believe there's something wrong with the way the data change is being notified.
I've already looked at many SO questions, however none of them have helped me to achieve what I need.
Any help is appreciated, thanks.
I suggest implementing an interface, say, IUpdateFromFragment with method, say, onUpdate(String message), then let activity implement that interface and inside the fragment just call something like ((IUpdateFromFragment)this.getActivity()).onUpdate(newMessageContent);
I realized the problem was that each time I replaced the fargment via the fragmentManager, the method setActivityView was being called again, which replaced the EditText content.
In order to avoid this, I manually removed the fragment (instead of replacing it), doing the following:
FragmentManager manager = this.selectTemplateFragment.getActivity().getFragmentManager();
manager.beginTransaction().remove(this.selectTemplateFragment).commit();
Update the fragment via transaction, then within the fragment1 class OnViewCreated, you can do mainView.editText1.setText("whatever");
The way you're doing this now, I'm surprised isn't throwing an exception since the view isn't inflated yet.
I'm new to Android development.
I created a simple master-detail app that starts with a simple, vertical scrolling list of topics.
When the user selects a topic, a details screen appears, replacing the first screen, with a list of details that pertain to the selected topic.
I want the title for the details screen to show the topic the user has selected on the first page, but haven't been able to solve the problem after working for almost a week.
All I need to know is, Can this be done? Not looking for someone to solve this for me, but maybe a hint or a link to a tutorial that shows how this can be done.
Note: I'd post a drawing of what I want to do, but I'm new here and don't have 10 reputation yet.
Thanks,
SonCoder
Not exactly sure what you want but either way..
-You have a listview. Each view (the data) in the listview should be a represented by a model. (aka a separate class containing specific information that you want to represent for each listitem.
-Write a custom list adapter (extend from base adapter).
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
In the getView method of this class you load the the String field of the model that you want in the textview.
-Make sure to use the viewholder pattern in the adapter above. I noticed the example doesnt use one. This speeds up scrolling in the list because there are much fewer calls to findViewById.
-in the list activity set up a View onClick listener. This should create an intent (for launching an activity) or a fragment transaction (for fragments). Send the instance of your entire model (will get from
parent.getAdapter().getItem(position);
in the on click method) into the detail activity.
-if you want to set a textview title just get the textview and set it from the model. It will be the same filed you inflated in the getView method of the adapter.
-if you want to set the titile in the actionbar set:
this.getActionBar().setTitle(title)
This is simple. Just send extra data in the intent that starts the activity and then in the activity's onCreate read the data and then use the setTitle(myString) method from the activity.
setTitle(String title) can be called from anywhere using the activity by the way.
So, your in your listadapter, then you set a listener on your view right? A simple onClickListener on the whole "root" view is just fine.
In the listener you say something in the ways of this:
Intent intent = new Intent(myActivity, MySubActivity.class);
intent.putExtra(key, titleName);
myActivity.startActivity(intent);
Note that the activity reference should be set in the constructor of the adapter and that the "key" String is something you get from your strings.xml. Do not duplicate these in code since if you change one and forget to change the others you might get some wierd NPEs.
Continue in your MySubActivity's onCreate()
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String key = getString(R.string.my_title_key);
String title = intent.getString(key);
setTitle(title);
}
NOTE: I'm not sure of all method names are correct and such but something like this.