I have an activity A. Once A has been loaded, on clicking a button in A adds a fragment F on A's home Layout. Now once inside F, if i am callinggetActivity().getSupportFragmentManager().popBackStack();, which infacts navigates again into the Activity A. Is there any way I can actually make some changes in the activity A once the fragment has been popbackstacked? I don't know which method is called in the activity once the fragment has been popbackstacked and you have your activity. Please help.
You can add OnBackStackChangedListener(). Just do something like this:
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
}
});
This callback will be called after each change on the back stack.
create and implement an interface in your activity
public class MyFragment extends Fragment {
OnFragmentCloseListener mCallback;
// Container Activity must implement this interface
public interface OnFragmentCloseListener {
public void onClosed(Bundle data);
}
//call this while closing the fragment
Bundle data = new Bundle();
data.putExtra("key"," value");
mCallback.onClosed(data);
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnFragmentCloseListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentCloseListener ");
}
}
}
In Your activity
public static class MainActivity extends Activity
implements MyFragment.OnFragmentCloseListener {
public void onClosed(Bundle data) {
//get the budle data here
}
}
Related
i try to set and interface between fragment and activity first this the interface in my activity
private PLRListener KListener;
public interface PLRListener{
void updateProgress(long e, long z);
void pause();
void play(long e, long z);
}
and i have viewPager with FragmentPagerAdapter now i set the listener on fragment
public class myfragment extends Fragment implements MainActivity.PLRListener {
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
((MainActivity)getActivity()).setListener(this);
} catch (ClassCastException e) {
throw new ClassCastException("www");
}
}
#Override
public void pause() {
//change background on fragment
}
#Override
public void play(long e, long z) {
//change text on fragment
}
}
now its work but work where on the next fragment not on the visible fragment
so its on callback function change the background and text of layout of the visible fragment
ex: i have three fragment and i start the application
fragment1 fragment2 fragment2
when iam on fragment2 and the callback function run its update on fragment3 when its on fragment1 and i run callback function its update fragment2
If you work with FragmentPagerAdapter you have to consider that this class will load more than one fragment because of OffscreenPageLimit which default value is 1 and can't be lower than 1. You are setting the listener everytime onAttach() of fragment is called. ((MainActivity)getActivity()).setListener(this);
I am launching a DialogFragment from my Fragment and listening to an event in MainActivity when the button is pressed in Dialog Fragment.
This is the listener interface defined in DialogFragment :
public interface NewDialogListener {
public void onDialogPositiveClick(String data);
}
Instantiating the listener in DialogFragment:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
// Instantiate the NoticeDialogListener so we can send events to the host
mListener = (NewDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
#Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
currentActivity = getActivity();
newDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(positiveButtonViewOnClickListener);
...
return newDialog;
}
Firing the listener when positive button in DialogFragmentis clicked:
private DialogInterface.OnClickListener positiveButtonOnClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mListener.onDialogPositiveClick("positive");
}
};
And then I capture the listener in MainActivity :
#Override
public void onDialogPositiveClick(String status) {
Fragment fragment = getVisibleFragment();
if (fragment instanceof NewListFragment) {
((NewListFragment)fragment).updateView();
}
}
This works if I haven't changes the rotation of the device. But If I changes the rotation of the device and do the same thing again, the control never reaches onDialogPositiveClick.
What is that changes when device is rotated that could cause this?
Since the listener is the activity itself, you can just use it directly in the onClick via a call to getActivity(). You can put a try catch on the call to be safe. No need to set it to a variable.
Have two fragments A and B, Fragment A has Textview and Fragment B has edittext and button.
Click on submit in FragmentB need to update textview in FragmentA with Edittext text.
How to do communication between fragment?
n this example, FragmentA call notify.
INotifier
public interface INotifier {
public void notify(Object data);
}
Utils
public class Utils {
public static INotifier notifier;
}
FragmentA
public FragmentA extends Fragment {
public void onCreateView(...) {
}
public void inSomeMethod() {
if (Utils.notifier != null) {
Utils.notifier.notify(data);
}
}
}
FragmentB
public FragmentB extends Fragment implements INotifier {
public void onCreateView(...) {
Utils.notifier = this;
}
#Override
public void notify(Object data) {
// handle data
}
}
You need to interact the activity first which will interact the second fragment. and also read this article on how to do it.
https://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
The communication between Fragments is done usinng Listeners. When you want to update fragment, use the listener to tell the MainActivity to update the second fragment as recommended by Google http://developer.android.com/training/basics/fragments/communicating.html. Create the interface in Fragment and Implement this in Activity
Listener in Fragment
public interface FragmentUpdateInterface {
void updateFragment(String newText);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (FragmentUpdateInterface ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FragmentUpdateListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
mCallback.updateFragment("New Text");
}
MainActivity
Implement fragment in MainActivity as
public static class MainActivity extends Activity
implements MyFragment.FragmentUpdateListener{
public void updateFragment(String newText) {
OtherFragment otherFrag = (OtherFragment)
getSupportFragmentManager().findFragmentById(R.id.other_fragment);
if (otherFrag != null) {
otherFrag.updateFragment(newText);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
OtherFragment otherFrag = new OtherFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
otherFrag.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, otherFrag);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
Hope this helps.
UPDATE:
You can also use LocalBroadcastManager.getInstance().sendBroadcast() to notify to the other fragment as well.
I have an activity with two fragments.
Fragment A does a complex operation during onResume(), and Fragment B needs fragment A to be finished the complex operation, or else user interaction with Fragment B will cause a crash.
I want to put a progressbar spinning object in this activity until Fragment A is complete, and then reveal the layout with Fragment A and Fragment B side by side.
But I am unsure how to expose the completion of Fragment A's onResume to the activity.
In Fragment A I do have a fragmentlistener set up
public void onAttach(final Activity activity) {
super.onAttach(activity);
try {
this.mListener = (TopicListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.getClass().getName()
+ " must implement TopicListener");
}
}
But now what, thanks.
As suggested on Android Developer here, I would suggest you to not couple the fragments and use a callback through your activity class.
do this:
public class MyFragmentOne extends Fragment{
#Override
onResume()
{
//Do the complex task
((MyActivity)getActivity()).fragmentTaskCompleted();
}
}
public class MyActivity extends Activity
{
public void fragmentTaskCompleted()
{
//Show second fragment
}
}
Use your callback to send you to the activity.
Example of using callbacks with a map fragment
private MapListeners mLocation;
public interface MapListeners{
public void onMarkerClick(Marker m);
public void onLocationChanged(Location location);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
mLocation = (MapListeners)activity;
}catch(ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement OnMarkerClick and OnLocationChanged");
}
}
public boolean onMarkerClick(Marker marker) {
//marker is clicked so send a call to the activity like this
mLocation.onMarkerClick(marker);
return true;
}
In the activity make sure you implement the interface, in this case it would be MapListeners
then when a marker was clicked the onMarkerClick method you created gets called
public void onMarkerClick(Marker m) {
//do something
}
Taking the default 'Master/Detail' flow template in Eclipse, and adding a third Fragment (let's call it Edit, launched from the pre-existing Detail Fragment) and I'm now looking to open the Edit Fragment when a user clicks on an item in the Detail Fragment.
I've implemented an interface on the Detail fragment, however depending on whether the application is on a Tablet or Phone (dual-pane or not), the Iterface requires to be implemented by either the Detail Activity, or the Main Activity in order to function. I assume this is due to the way that the template implements opening of the Detail Fragment as an activity when the device is not in dual-pane mode.
Have I implemented this incorrectly, or is there a best practice that would allow me to unify the implementation of the interfaces into the main activity?
Here are some reduced snippets from the Master and Detail Fragments, showing the requirement for dual-implementation of the Detail Fragments interface.
Code for WaveListWactivity.java (first Fragment)
public class WaveListActivity extends FragmentActivity implements
WaveListFragment.Callbacks,WaveDetailFragment.Callbacks {
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wave_list);
if (findViewById(R.id.wave_detail_container) != null) {
mTwoPane = true;
((WaveListFragment) getSupportFragmentManager().findFragmentById(
R.id.wave_list)).setActivateOnItemClick(true);
}
}
//Interface from WaveListFragment
#Override
public void onWaveSelected(int id) {
if (mTwoPane) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.wave_detail_container, new WaveDetailFragment()).commit();
} else {
Intent detailIntent = new Intent(this, WaveDetailActivity.class);
startActivity(detailIntent);
}
}
//Interface from WaveDetailFragment
#Override
public void onItemSelected(int id) {
if (mTwoPane) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.wave_detail_container, new WaveEditFragment()).addToBackStack(null).commit();
} else {
Intent detailIntent = new Intent(this, WaveDetailActivity.class);
startActivity(detailIntent);
}
}
}
Code for WaveDetailActivity.java (second Fragment)
public class WaveDetailActivity extends FragmentActivity implements WaveDetailFragment.Callbacks {
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wave_detail);
if (findViewById(R.id.wave_detail_container) != null) {
mTwoPane = true;
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.wave_detail_container, new WaveDetailFragment()).commit();
}
}
//Callback from WaveDetailFragment
#Override
public void onItemSelected(int id) {
if (mTwoPane) {
getSupportFragmentManager().beginTransaction().replace(R.id.wave_detail_container, new WaveEditFragment()).addToBackStack(null).commit();
} else {
Intent detailIntent = new Intent(this, WaveEditActivity.class);
startActivity(detailIntent);
}
}
}
I think you may be slightly confused as to the difference between FragmentActivity, Fragments and the callback interfaces that you need to implement on your Activity. From the looks of it, all the code snippets are Activity classes and not Fragments. I would expect a Fragment to look something like:
/** From http://developer.android.com/training/basics/fragments/communicating.html */
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
And then your Activity:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
}
}
The overall 'flow' of this should be:
Fragments act as blobs of UI code with callbacks for all the interesting stuff.
Callbacks implemented by Activity.
The overall number of actions you can do depends on the fragments which depends on the size of your screen (so you may have 2 fragments which feed into a single Activity). The logic for determining whether to show one or two fragments should be done in the Activity.