In my app, I have an activity that has two fragments in actionbar tabs navigation mode, just like the android developer site example.
in my first fragment I have a listview (which has it's own adapter ) and each item of the listview has a button called +1. I want to refresh the second fragment that shows the items in listview in first fragment that their +1 button's clicked.
I know i have to use interfaces. but I cant figure how to use them. where do I have to define the interface? how to use it? and how to access it from the activity to refresh the second fragment?
a quick help would be great. thanks.
If you want it on List Item Click
Fragment A:
public class FragmentA extends ListFragment {
OnItemSelectedListener mListener;
...
// Container Activity must implement this interface
public interface OnItemSelectedListener {
public void onItemSelected(int position);
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnItemSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnItemSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onItemSelected(position);
}
}
ContainerActivity:
public class ContainerActivity extends FragmentActivity
implements FragmentA.OnItemSelectedListener
{
//...
public void onItemSelected(int Position/*pass anything which u want*/)
{
SecondFragment second_fragment = (SecondFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentB);
if(second_fragment !=null)
{
second_fragment.UpdateUI(Position);
}
}
}
Second Fragment:
public class SecondFragment extends Fragment {
...
public void UpdateUI(Position)
{
}
}
Hope this helps. On click of a Button inside each listitem might be bit difficult, but try the same approach. May be you have to write the interface declaration and call in your custom adapter.
Related
I have a Fragment which contains viewpager.
inside ViewPager I have 3 more Fragments, Fragment-A,Fragment-B, and Fragment-C.
Inside Fragment A I have a Button, in Button onClick() I want to change the current item to Fragment C.
How can I achieve it? Please help
If button is not in main fragment, you'll have to define an interface to communicate between your main fragment and sub fragments i.e fragment A B C.
public interface GoToNextFragment {
void onGoToFragment(int index);
}
Your MainFragmet will have to implement this interface and the method that goes with it :
public class MainFragment extends Fragment implements GoToNextFragment {
//Your regular methods...
#Override
public void onGoToFragment(index) {
if (myAdapter != null) {
myAdapter.setCurrentItem(index);
}
}
Still in your MainFragment, set the interface on your fragments :
fragment1.setInterface(this);
fragment2.setInterface(this);
In your Fragments, add the setInterface method :
private GoToNextFragment mInterface;
public void setInterface(GoToNextFragment i) {
mInterface = i;
}
And finally in fragment a, trigger the effect with :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mInterface != null) {
mInterface.onGoToFragment(2);
}
});
In your clickHandler add this method viewpager.setCurrentItem(int index)
viewpager.postDelayed(new Runnable() {
#Override
public void run() {
viewpager.setCurrentItem(2);
}
}, 100);
Here 2 is your Fragment C index.
Update
No need to create object of viewpager in Fragment A.
Just create one interface that extend in your Activity or Fragment which contain ViewPager and implement it into Fragment A.
i am just working with fragments for the 1st time, i have a checkbox inside a fragment and a submit button inside my main activity. what i want to do is when i press submit button i want to toast a message whether the checkbox item is checked or not?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Spinner Dspinner;
private Button Subbtn;
ArrayAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Subbtn = (Button)findViewById(R.id.button);
adapter = ArrayAdapter.createFromResource(this, R.array.spinner_options, android.R.layout.simple_spinner_item);
spinnerListner();
}
public void spinnerListner(){
Dspinner = (Spinner)findViewById(R.id.spinner);
Dspinner.setAdapter(adapter);
Dspinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
getSupportFragmentManager().beginTransaction().replace(R.id.frag, BlankFragment.newInstance()).addToBackStack(null).commit();
break;
case 1:
getSupportFragmentManager().beginTransaction().replace(R.id.frag, BlankFragment2.newInstance()).addToBackStack(null).commit();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
);
}
}
BlankFragment.java
public class BlankFragment extends Fragment {
public BlankFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
public static Fragment newInstance() {
BlankFragment fragment = new BlankFragment();
return fragment;
}
}
BlankFragment2.java
public class BlankFragment2 extends Fragment {
public BlankFragment2(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank_2, container, false);
}
public static Fragment newInstance() {
BlankFragment2 fragment = new BlankFragment2();
return fragment;
}
}
You can use interface to communicate back to MainActivity.
Create a interface and implement it on MainActivity.
Pass the implemented interface to fragment and store it in the fragment
Then When your checkbox state change check that the stored interface is null or not if not null then call the implemented method
of the interface, which is actually implemented in MainActivity.
This way you can communicate back to MainActivity. In MainActivity store your checkbox state and do what you want to do in button press.
Interface
public interface OnStateChanged {
public void onChange(int state);
}
Implement it on MainActivity like
MainActivity implements OnStateChanged {
#Override
public void onChange(int state){
// store your data here
}
Create a variable for OnStateChanged interface and function in Fragment that will pass the interface
In Fragment:
OnStateChanged mListener;
public void setOnStateChangeListener(OnStateChanged listener){
mLinstener = listener;
}
When checkbox state change call the interface function
In Fragment:
//...if state change...
if(mListener!= null) {
mListener.onChange(/*your value*/);
}
Pass the implemented interface instance in MainActivity to fragment
In MainActivity:
fragment.setOnStateChangeListener(this);
There are several ways to realize this function. The easiest way is Defining an interface in your Activity, and let the Fragment implements it.(Or you can define a interface individually and let the Activity implements it, it's the similar solution)
For more solutions you can Google "Fragment and Activity Interaction".
I just can offer you some fragmentary code since I cannot find specific variable names.
First, defining a Interface in your Activity like this:
public static class MainActivity extends AppCompatActivity{
...
//Container Activity must implement this interface
public interface CheckBoxStateCallback{
public Boolean getTheState();
}
...
Second, let your fragments implements it:
public class BlankFragment extends Fragment implements CheckBoxStateCallback{
public BlankFragment(){
}
#Override
public Boolean getTheState(){
//return your checkbox state
}
...
Last, you need to add a click listener onto your Button in Activity:
...
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Boolean b = BlankFragment.newInstance().getTheState();
//then you can make a toast
}
});
...
In MainActivity you would implement an interface CheckboxStatusObserver which we define with a method checkBoxChanged.
public class MainActivity extends AppCompatActivity implements CheckboxStatusObserver{
// other methods
void checkBoxChanged(boolean checkedStatus){
Toast.makeText(getContext(), "status " + checkedStatus, Toast.LENGTH_LONG).show();
}
public interface CheckboxStatusObserver{
void checkBoxChanged(boolean checkedStatus);
}
}
In the Fragment, we would get a reference to the CheckboxStatusObserver as the parent Activity. Then while inflating the contents of the Fragment, we can set up a listener to detect the on change of the checkbox(s). Then we would call the observer.checkBoxChanged(checkedStatus); and pass it the checked status of the checkbox.
public class BlankFragment extends Fragment {
private CheckboxStatusObserver observer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
observer = (CheckboxStatusObserver) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
// Find the checkbox instace using view.findViewById();
// Setup change listener on checkbox instance and notify the observer
{
observer.checkBoxChanged(checkedStatus);
}
return view;
}
}
Whenever the checkbox status changes, the method in the MainActivity will get invoked.
See below links for more information:
https://stackoverflow.com/a/25392549/592025
https://developer.android.com/training/basics/fragments/communicating.html
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Create an Interface in Your MainActivity and click listeners as below
try {
((OnClick) this).onSubmitClicked();
} catch (ClassCastException cce) {
cce.printStackTrace();
}
public interface OnClick {
public void onSubmitClicked();
}
Now implement listeners in your Fragment thus you will get onSubmitClicked implemented method as below Enjoy!
public class BlankFragment extends Fragment implements MainActivity.OnClick{
#Override
public void onSubmitClicked() {
//do something here
}
}
This is yet another way different from what i commented that day this might meet your need
In Main Activty
Blank1Fragment fragment1 = new Blank1Fragment();
Blank2Fragment fragment2 = new Blank2Fragment();
Subbtn..setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(position==0)
fragment1.function();
else if(position==1)
fragment2.function();
}
);
in OnitemClick of spinner
switch (position){
case 0:
position=0;
getSupportFragmentManager().beginTransaction().replace(R.id.frag, fragment1).addToBackStack(null).commit();
break;
case 1:
position=1;
getSupportFragmentManager().beginTransaction().replace(R.id.frag, fragment2).addToBackStack(null).commit();
break;
}
}
Each fragment will have
public class Blank1Fragment extends Fragment {
....
public void function(){
//check which checkbox selected and toast;
}
}
public class Blank2Fragment extends Fragment {
....
public void function(){
//check which checkbox selected and toast;
}
}
I have a Fragment with a "pick a year" button. This button adds a ListFragment to the backstack, where the user can pick a year. Once a year is chosen, I want to dispose of the ListFragment and return to the first fragment. What is the best way to update the first fragment, with the data that was selected in the ListFragment?
TL;DR: Fragment1 opens Fragment2, user chooses option in Fragment2. How do I update Fragment1 with this data?
My current solution is a public class with static members, but I'm wondering if Android has a better way.
All Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly. [Source]
Define an interface in Fragment2, and implement this interface in the host Activity. When you call the interface method from Fragment2, you can then access Fragment1 from inside the interface method on the Activity and pass the appropriate data to Fragment1 via its public methods.
Create an interface:
public class Fragment2 extends ListFragment {
OnItemSelectedListener mCallback;
public interface OnItemSelectedListener {
public void onItemSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnItemSelectedListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnItemSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onItemSelected(position);
}
}
Add implements Fragment2.OnItemSelectedListener to your activity definition, and define the onItemSelected method:
public void onItemSelected(int position) {
Fragment1 fragment = (Fragment1)
getSupportFragmentManager().findFragmentById(R.id.fragment1);
if (fragment != null) {
fragment.updateValue(position);
}
}
I have a Fragment FR1 that contains several Nested Fragments; FRa, FRb, FRc. These Nested Fragments are changed by pressing Buttons on FR1's layout. Each of the Nested Fragments have several input fields within them; which include things like EditTexts, NumberPickers, and Spinners. When my user goes through and fills in all the values for the Nested Fragments, FR1 (the parent fragment) has a submit button.
How can I then, retrieve my values from my Nested Fragments and bring them into FR1.
All Views are declared and programmatically handled within each Nested Fragment.
The parent Fragment, FR1 handles the transaction of the Nested Fragments.
I hope this question is clear enough and I am not sure if code is necessary to post but if someone feels otherwise I can do so.
EDIT 1:
Here is how I add my Nested Fragments:
tempRangeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, tempFrag)
.commit();
}
});
scheduleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, scheduleFrag)
.commit();
}
});
alertsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, alertsFrag)
.commit();
}
});
submitProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
constructNewProfile();
}
});
where my constructNewProfile() method needs the values from my Nested Fragments.
public Fragment tempFrag = fragment_profile_settings_temperature
.newInstance();
public Fragment scheduleFrag= fragment_profile_settings_schedules
.newInstance();
public Fragment alertsFrag = fragment_profile_settings_alerts
.newInstance();
The above refers to the fields of the parent fragment; and how they are initially instantiated.
The best way is use an interface:
Declare an interface in the nest fragment
// Container Activity or Fragment must implement this interface
public interface OnPlayerSelectionSetListener
{
public void onPlayerSelectionSet(List<Player> players_ist);
}
Attach the interface to parent fragment
// In the child fragment.
public void onAttachToParentFragment(Fragment fragment)
{
try
{
mOnPlayerSelectionSetListener = (OnPlayerSelectionSetListener)fragment;
}
catch (ClassCastException e)
{
throw new ClassCastException(
fragment.toString() + " must implement OnPlayerSelectionSetListener");
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
onAttachToParentFragment(getParentFragment());
// ...
}
Call the listener on button click.
// In the child fragment.
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.tv_submit:
if (mOnPlayerSelectionSetListener != null)
{
mOnPlayerSelectionSetListener.onPlayerSelectionSet(selectedPlayers);
}
break;
}
}
Have your parent fragment implement the interface.
public class Fragment_Parent extends Fragment implements Nested_Fragment.OnPlayerSelectionSetListener
{
// ...
#Override
public void onPlayerSelectionSet(final List<Player> players_list)
{
FragmentManager fragmentManager = getChildFragmentManager();
SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag)fragmentManager.findFragmentByTag("Some fragment tag");
//Tag of your fragment which you should use when you add
if(someOtherNestFrag != null)
{
// your some other frag need to provide some data back based on views.
SomeData somedata = someOtherNestFrag.getSomeData();
// it can be a string, or int, or some custom java object.
}
}
}
Add Tag when you do fragment transaction so you can look it up afterward to call its method. FragmentTransaction
This is the proper way to handle communication between fragment and nest fragment, it's almost the same for activity and fragment.
http://developer.android.com/guide/components/fragments.html#EventCallbacks
There is actually another official way, it's using activity result, but this one is good enough and common.
Instead of using interface, you can call the child fragment through below:
( (YourFragmentName) getParentFragment() ).yourMethodName();
The best way to pass data between fragments is using Interface. Here's what you need to do:
In you nested fragment:
public interface OnDataPass {
public void OnDataPass(int i);
}
OnDataPass dataPasser;
#Override
public void onAttach(Activity a) {
super.onAttach(a);
dataPasser = (OnDataPass) a;
}
public void passData(int i) {
dataPasser.OnDataPass(i);
}
In your parent fragment:
public class Fragment_Parent extends Fragment implements OnDataPass {
...
#Override
public void OnDataPass(int i) {
this.input = i;
}
btnOk.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("0");
((Fragment_Fr1) fragment).passData();
}
}
}
You can use share data between fragments.
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item -> {
// Update the UI.
});
}
}
More Info ViewModel Architecture
You can use getChildFragmentManager() and find nested fragments, get them and run some methods to retrieve input values
Check for instanceOf before getting parent fragment which is better:
if (getParentFragment() instanceof ParentFragmentName) {
getParentFragment().Your_parent_fragment_method();
}
Passing data between fragments can be done with FragmentManager. Starting with Fragment 1.3.0-alpha04, we can use setFragmentResultListener() and setFragmentResult() API to share data between fragments.
Official Documentation
Too late to ans bt i can suggest create EditText object in child fragment
EditText tx;
in Oncreateview Initialize it. then create another class for bridge like
public class bridge{
public static EditText text = null;
}
Now in parent fragment get its refrence.
EditText childedtx = bridge.text;
now on click method get value
onclick(view v){
childedtx.getText().tostring();
}
Tested in my project and its work like charm.
I am using sliding menu/drawer pattern in my app. So the main activity has a leftView which is a ListFragment named topicsFragment() which loads set of topic items. When an item/topic is clicked it replaces the fragment on main view by calling the FeedsFragment(tag). FeedsFragment uses arraylist adapter to load the feeds which has various clickable items in each list item. I want to fetch another instance on the feedsFragment(tag) when an item is clicked within a list item.
holder.contextView= (TextView) newsView.findViewById(R.id.arcHeader);
if (item.hasArc()) {
holder.contextView.setVisibility(View.VISIBLE);
String arc;
try {
arc=item.getarc();
holder.contextView.setText(arc);
holder.contextView.setOnClickListener(new View.OnClickListener() {
//currently it loads a class
#Override
public void onClick(View v) {
Intent i = new Intent(context, SomeClass.class);
i.putExtra("tag", arc);
context.startActivity(i);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
} else {
holder.contextView.setVisibility(View.GONE);
}
Currently it loads a new class. I want to define a fragment and then pass to main activity to replace with the current view but I cant use getSupportFragmentManager() inside an adapter class but only in a fragment or fragment activity. What should be an alternative to sweeping in a fragment from an adapter?
What I did was create this method in my main activity and just called it from other classes to change the fragment:
public void switchContent(Fragment fragment) {
mContent = fragment;
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment).commit();
slidemenu.showContent();
}
Solved it by using the context passed in the list adapter:
#Override
public void onClick(View v) {
Fragment newFragment = new ListFragmentClass(tag);
if (newFragment != null)
switchFragment(newFragment);
}
private void switchFragment(Fragment newFragment) {
if (context == null)
return;
if (context instanceof MainActivity) {
MainActivity feeds = (MainActivity) context;
feeds.switchContent(newFragment);
}
}
Here switchContent is method defined in your main activity for switching/replacing fragment as given in answer by Justin V.
Pass getFragmentManager() as a parameter in constructor of your adapter and use that.
Use an Interface to connect your side drawer ListFragment to the main activity. For example:
public class LeftDrawer extends ListFragment{
private DrawerCallback mCallback;
public interface DrawerCallback{
public void onListClick(String tag);
}
public void setCallback(DrawerCallback callback){
mCallback = callback;
}
}
As Fragments should have an empty constructor, use a public method within your Fragment to set the callback before completing the FragmentTransaction adding it to your drawer. At this point all that is left is notifying your Fragment that a click has occurred. What you should do is actually catch the click in your ListFragment directly rather than adding on onClickListener to every view in your adapter.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
/*
* Get item at the clicked position from your adapter and
* get its string tag before triggering interface
*/
mCallback.onListClick(tag);
}
Use the onListItemClick method to do this. You will get the list position that was clicked and can easily then get that item from your adapter and get its tag value to pass back to your host activity.