I have an activity that call a dialogfragment, how can I get the fragment result when it dismissed? Is there any method for fragment like onActivityResult?
You have to implement a callback to know the response of your dialog fragment. If you want to implement this, create an interface in your dialog fragment. Like this example:
interface OnResultDialog{
public void onDialogRespond(Object result);
}
private OnResultDialog mCallback;
And implement this interface in your activity. In the onAttach of your DialogFragment, set the activity as an OnResultDialog:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallback = (OnResultDialog)activity;
}
Then, before or after you dismiss your dialog, you can call the method of your callback and pass the parameters you need. Like this:
mCallback.onDialogRespond(object);
Hope it helps
Related
I have Activity in my app with few fragments in it. One of these fragments has a DialogFragment, it called by button click. DialogFragment has 3 buttons - positive, negative and neutral.
public class CompanyNotConnectedToSRDialog extends DialogFragment {
public static final String TAG = CompanyNotConnectedToSRDialog.class.getSimpleName();
private NotConnectedDialogListener mNotConnectedDialogListener;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity(), R.style.DefaultAlertDialogTheme)
.setTitle("Register")
.setMessage("Do you really want to register?")
.setNeutralButton("Skip", (dialog1, which) -> {
mNotConnectedDialogListener.onSkipBtnNotConnectedDialogPressed();
})
.setNegativeButton("Cancel", null)
.setPositiveButton("Register", (dialog12, which) -> {
mNotConnectedDialogListener.onSendBtnNotConnectedDialogPressed();
})
.create();
}
public interface NotConnectedDialogListener {
void onSkipBtnNotConnectedDialogPressed();
void onSendBtnNotConnectedDialogPressed();
}
public void setListener(NotConnectedDialogListener listener) {
this.mNotConnectedDialogListener = listener;
}
As you can see I created public interface that contains two methods for my skip and register buttons (cancel button listener is null so it doesn't matter) and the Setter for this listener.
Then I implemented this interface in my fragment that calls this dialogFragment, I Overrided methods and called dialogFragment like this:
if (mNotConnectedDialog == null) {
mNotConnectedDialog = new CompanyNotConnectedToSRDialog();
mNotConnectedDialog.setListener(this);
mNotConnectedDialog.show(getActivity().getFragmentManager(), CompanyNotConnectedToSRDialog.TAG);
} else {
mNotConnectedDialog.show(mActivity.getFragmentManager(), CompanyNotConnectedToSRDialog.TAG);
mNotConnectedDialog.setListener(this);
}
The problem is I get NullPointerException if I press the button in my parent Fragment to show DialogFragment, rotate screen and press any button in my DialogFragment, because my listener is null.
java.lang.NullPointerException: Attempt to invoke interface method 'void com.myapp.ui.object.create.dialogs.CompanyNotConnectedToSRDialog$NotConnectedDialogListener.onSendBtnNotConnectedDialogPressed()' on a null object reference
at com.myapp.ui.object.create.dialogs.CompanyNotConnectedToSRDialog.lambda$onCreateDialog$1(CompanyNotConnectedToSRDialog.java:31)
How to handle these clicks and set listeners if this solution is wrong?
PS: please don't tell me about android:configChanges.
So the current solution doesn't work because when you rotate the dialog fragment is destroyed and recreated. So setListener isn't called. The solution depends on if your listener is an activity or another fragment.
If it's an activity you can override onAttach in your DialogFragment and set the listener there. If your listener is a fragment then in your OnCreateDialog method you can look the fragment up by the tag and set the listener that way. For example.
Fragment listenerFragment = getActivity().getSupportFragmentManager().findFragmentByTag(getString(R.string.your_listener_fragment_tag));
if( listenerFragment instanceOf NotConnectedDialogListener ) {
listener = (NotConnectedDialogListener) listenerFragment;
} else {
//Handle what to do if you don't have a listener here. Maybe dismiss the dialog.
}
Yes, after orientation change your listener is null. It's easiest to do the callback to the activity:
public static class DialogFragmentA extends DialogFragment {
// Container Activity must implement this interface
public interface NotConnectedDialogListener {
public void onX();
}
NotConnectedDialogListener mListener;
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (NotConnectedDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement NotConnectedDialogListener");
}
}
...
}
Now you can call mListener.onX etc. in your dialog anywhere, also after orientation change. Your container Activity must implement the interface and will receive the method call.
https://developer.android.com/guide/components/fragments.html#EventCallbacks
I have an activity and a fragment. If I click a button then a fragment is called. Upon the result I got from the fragment I need some networking call to perform using volley. But I can't do any networking call from activity unless I call this within onClick() method.
I tried to perform networking from within onClick() of the fragment but that did not worked too.
How can i perform networking from the activity upon the result I got from the fragment? Do I must call from within onClick()?
This is the fragment
This is the Activity
I think that you can use callback.
Create intefrace and declare method saveResult() in it.
public interface YourInterface{
void saveResult();
}
After that your Activity must implement this interface and add your code for save result in database in saveResult method body
public class YourActivity implements YourInterface{
#override
void saveResult(){
//your code here
}
}
And finnaly in your fragment call method when you whant or when your fragment is ready.You can call method with help of
callBack.saveResult();
You must override onAttach in your fragment and there must initialize your callback
YourInterface callback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(activity instanceof YourInterface ) {
callback = (YourInterface ) activity;
}
}
Try with other on click method in at your onCreate method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mark_distribution);
assign_buttton=(Button)findViewById(R.id.assign_marks);
view_buttton=(Button)findViewById(R.id.view_marks);
update_buttton=(Button)findViewById(R.id.update_marks);
//Like this-->>>
update_buttton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
marks_type=(String)assigned_marks_type.getText().toString();
marks=Integer.parseInt(assigned_marks.getText().toString().trim());
callback.saveResult(marks_type,marks);
}
});
//********************/
Intent i=getIntent();
course_title= i.getExtras().getString("COURSE_TITLE");
}
Hope to help you!
I have an activity which calls another fragmentA .Now this fragmentA calls another fragmentB .Now I want to transfer data from fragmentB to my activity
check this: Communicating with Other Fragments
Define an Interface (In fragment)
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.
Here is an example of Fragment to Activity communication:
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");
}
}
...
}
Now the fragment can deliver messages to the activity by calling the onArticleSelected() method (or other methods in the interface) using the mCallback instance of the OnHeadlineSelectedListener interface.
For example, the following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
mCallback.onArticleSelected(position);
}
Implement the Interface (in activity)
In order to receive event callbacks from the fragment, the activity that hosts it must implement the interface defined in the fragment class.
For example, the following activity implements the interface from the above example.
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
}
}
PS1: EventBus works for you, but use it carefully if you need, it may make your code harder to read.
PS2: Don't pass an activity instance in Fragment.newInstance() and communicate using it. The activity instance may be destroyed in background. Get activity instance in Fragment.onAttach() like the example, the framework will handle the destroy & recreate & rebind for you.
You can get the Activity instance by overriding onAttach() method
Method: 1
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
this.activity=(ActivityName) activity;
}
and
activity.setdata(yourdata);
or
Method : 2
((ActivityName)getActivity()).setdata(yourdata);
In these ways you need to create a setter method in your activity
It is easiest way to get callback from any fragment to its parent activity .Very well explained by Dev Doc here
You can get the instance of the activity by calling getActivity() in fragmentB and pass the data using an interface.
You could use EventBus if you think that, you will need a similar functionality in different parts of the app and you don't want to write many interfaces for this porpoise.
You could use https://github.com/greenrobot/EventBus
Example:
Add compile 'de.greenrobot:eventbus:2.4.0',
Register on activities
OnCreate -
EventBus.getDefault().register(this);
and OnDestroy-
EventBus.getDefault().unregister(this);
Than add a method with a receiving object parameter and with onEventMainThread name:
public void onEventMainThread(YourObject name) {...}
Now from any Fragament you can call
EventBus.getDefault().post(yourObjectInstance);
And activity will detect it.
Or you could use RxJava to get similar effect -
http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/
I am creating a custom dialog class in which I extend the default Dialog. I am doing some work there. Once the user closes the dialog, how can my activity know that the dialog is closed and time to update the screen views with results?
Do I pass an instance from my activity to the Dialog class so I can call a public method on it? Or is there a better design?
Thank you
what I'll do is this:
Create an Interface, for example: OnDialogCloseListener, with a method called onDialogClose()
The activity have to implement that interface and override the onDialogClose() method
Create an attribute in yout Dialog class of OnDialogCloseListener type and a constructor method and when you create the Dialog pass the activity as a parameter.
OnDialogCloseListener listener;
public MyDialog(OnDialogCloseListener listener) {
this.listener = listener;
}
Now in your onClick method of the close button of your Dialog call the method of the interface. Ex.:
listener.onDialogClose();
And finally in your activity class in the method that you override from OnDialogCloseListener do whatever you want when the Dialog is close.
Note: You can create all the methods that you want in the interface a call each one whatever you want, not only when the dialog is close, you may have other events that you want check when raised.
Hope that can help you
From the docs: http://developer.android.com/guide/topics/ui/dialogs.html
create an interface in your dialog class:
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
Register a listener in onAttach() :
#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 = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
And implement that interface in your calling activity.
A dialog overrides several methods that sense when the dialog is closing. The include
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
public void setOnCancelListener(#Nullable OnCancelListener listener) {
super.setOnCancelListener(listener);
}
#Override
protected void onStop() {
super.onStop();
}
These methods all detect that action of closing a dialog. However, the most efficient one that I suggest you use is
#Override
public void onDetachedFromWindow() {
Toast.makeText(getContext().getApplicationContext(), "Dialog had disappeared", Toast.LENGTH_SHORT).show();
super.onDetachedFromWindow();
}
Here is what I would like to do:
1) Inside an Activity a dialog is shown. I use DialogFragment and FragmentManager for this, by calling:
dialogFragment.show(fragmentManager, "edit_task_list");
2) Inside the Dialog I have layout with a custom Button. I would like to perform some action when the button is clicked and later close the dialog.
How should I connect everything? I see two options:
1) onclick attribute in the Button and a method inside the Actvity. That was my original plan, but I don't how to get the Dialog from the Activity to dismiss it. Even if this is not the right way, how could this be done? I would like to understand how this works.
2) set on click listener on the button when the Dialog is created in DialogFragment. This will require me to pass some context from the Activity to the DialogFragment, so I would like to avoid it (and keep the DialogFragment as simple as possible).
Which of those options should I take?
Number 2 Doesn't require you to pass any context (and you shouldn't). You define an interface that can act as a contract between fragments and activities and make your activity implement it.
From your dialog and in your button.onClick(), you do something like this (untested code):
if ( getActivity() != null
&& !getActivity().finishing()
&& getActivity() instanceOf YourInterface) {
((YourInterface)getActivity()).onSomeNiceMethod();
dismiss(); // close the dialog (if this is what you want).
}
The interface looks like:
public interface YourInterface {
void onSomeNiceMethod();
}
And your Activity…
public class YourActivity implements YourInterface {
void onSomeNiceMethod() {
// Hey! The Button In The Dialog Has Been Pressed!
}
}
All Activity and Fragment classes have a built-in callback method for you to use when you start another Activity, Fragment, Dialog, or DialogFragment.
void onActivityResult(int requestCode, int resultCode, Intent data)
Since you want to start the Dialog from an Activity, using the Dialog class is better than the DialogFragment class. The latter is better for starting a dialog from a Fragment, because it has two methods for communicating back to the Fragment (get/set TargetFragment())
The Dialog class has the getOwnerActivity() method. This is the Activity you use when creating the Dialog with one of its constructors.
You set a onClickListener on the button in the Dialog class. To pass the result back to the Activity:
getOwnerActivity().onActivityResult(intIdentifyingme, Activity.RESULT_OK,
intent);
dismiss(); // close the dialog
You put additional info you want to send in an Intent.
1) onclick attribute in the Button and a method inside the Actvity.
That was my original plan, but I don't how to get the Dialog from the
Activity to dismiss it. Even if this is not the right way, how could
this be done? I would like to understand how this works.
Basically your Activity has to remember/know which dialog is active at the moment with something like curDialog=dialogFragment;, then when handling the button onclick action you'll know which dialog to dismiss. But this is really not a good idea since basically the Button View would "leak" from your DialogFragment to your Activity, which breaks object encapsulation.
2) set on click listener on the button when the Dialog is created in
DialogFragment. This will require me to pass some context from the
Activity to the DialogFragment, so I would like to avoid it (and keep
the DialogFragment as simple as possible).
As a previous answer mentioned, you don't need to pass any Context to it, especially since you can get the Activity by calling getActivity().
The solution depends on whether or not this dialog would be used by multiple Activities:
Used by a single Activity: #Martin's solution will work just fine
Used by multiple Activity: abstraction can be used such that only the user's decision is passed to a listener. This is a (modified) solution I came up for the same problem:
public class BaseDialogFragment extends DialogFragment {
protected TextView dialogEn;
protected Button dialogYes;
private Button dialogNo;
protected OnSelectListener listener;
public interface OnSelectListener {
public void onSelect(int type, boolean yes);
}
public void setOnSelectListener(OnSelectListener listener) {
this.listener = listener;
}
public BaseDialogFragment() {
super();
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_confirm, container, false);
dialogYes = (Button) v.findViewById(R.id.yes);
dialogNo = (Button) v.findViewById(R.id.no);
dialogEn = (TextView) view.findViewById(R.id.dialog_en);
dialogEn.setText(getArguments().getString("text_en"));
dialogYes.setOnClickListener(this);
dialogNo.setOnClickListener(this);
return v;
}
public void onClick(View v) {
if (listener != null) {
listener.onSelect(getArguments().getInt("type"),
v == dialogYes ? true : false);
}
getDialog().dismiss();
}
}
To use it some additional info needs to be provided:
Bundle bundle = new Bundle();
bundle.putInt("type", type); //type: an unique integer value that helps differentiate result from different dialogs
bundle.putString("text_en", en); //en: String to be displayed
dialog.setArguments(bundle);
dialog.setOnSelectListener(this);
So if the type value above is set to 115, then a dialogYes button click would trigger public void onSelect(int type, boolean yes) method to be called with 115 and true as the 1st & 2nd parameters.
Your first point about the onClick attribute in the xml should be avoided. Because handling a Dialog that way could be really painfull if you respect events like screen rotation or a setup with multiple dialogs. This leads into leaked window errors most of the time and needs unnecessary code overhead to avoid this. Because you have to keep track of the Dialog which is actually shown yourself.
To be able to dismiss the Dialog this way you can use the Tag you setted as you called dialogFragment.show(fragmentManager, "edit_task_list");
DialogFragment frag = (DialogFragment)getFragmentManager().findFragmentByTag("edit_task_list");
if(frag != null)
frag.dismiss();
The proper solution is to use an interface as a callback for the communication between the DialogFragment and the Activity. This keeps the Dialog modular and the code easy. Here is an example from the docs. For this you don't need a Context. You simply pass the interface to the dialog in the onAttach() callback. It has a reference of the Activity as a parameter, which called that Dialog.
// Example interface for the communication
public interface OnArticleSelectedListener {
public void onButtonClicked(/*any Parameters*/);
}
public static class FragmentA extends DialogFragment {
OnArticleSelectedListener mListener;
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity; // get the interface of the Activity
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnArticleSelectedListener");
}
}
...
}
Handle the Button click in the Dialog and call dismiss() in it, that the Dialog can dismiss itself. Have a look at this question why to use dismiss() instead of getDialog().dismiss().
yourButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
if(mListener != null) // check if the listener is still valid
mListener.onButtonClicked(...); // calls the Activity implementation of this callback
dismiss(); // dismiss the Dialog
}
});
In onPause() of the Dialog set the reference of the interface to null. This way you can be sure that the callback will only be used if the Dialog is showing.
Your Activity looks something like this to be able to handle the callback:
public class MyActivity extends Activity implements OnArticleSelectedListener{
...
#Override
public void onButtonClicked(...){
// your implementation here
}
}
I don't know your overall setup but if you would use an AlertDialog a click on the Buttons dismiss the Dialog automatically when the method returns.