问题
How can I call finish() and other non static methods from a DialogFragment in the activity that created it? I have tried passing messages from the OnClickLisener in the DialogFragment, to no avail.
I have a really simple app, conssting of a MainActivity and DialogFragment:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity);
showDialog();
}
public void showDialog() {
DialogFragment newFragment = new ConfirmDialog();
newFragment.show(getFragmentManager(), "dialog");
}
} And the Dialog is again very simple:
public class ConfirmDialog extends DialogFragment {
@Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Confirm you want to continue?")
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
.setNegativeButton("No.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Do nothing in MainActity
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
回答1:
There are many options. One of them is define an interface with a single method inside.
- Have the dialog caller implement that interface.
- Keep a global variable pointing to the caller.
- Set the variable in the
onAttach(Activity activity)
method. - Null that variable in the
onDetach()
method. - Call the variable (interface member) method in the
onClick
.
Example:
public class MainActivity extends Activity implements MyInterface {
// ...
@Override
public void onChoose() { finish(); }
}
And inside ConfirmDialog
:
public static interface MyInterface {
public void onChoose();
}
private MyInterface mListener;
@Override
public void onAttach(Activity activity) {
mListener = (MyInterface) activity;
super.onAttach(activity);
}
@Override
public void onDetach() {
mListener = null;
super.onDetach();
}
And then call mListener.onChoose()
anywhere inside your class.
I know this has been marked as accepted, but I figured I could provide more feedback to the discussion.
A note about using or not interfaces. Andy's answer works just as right as mine, hence why I said "There are many options. One of them is...".
However, the reason why I prefer interfaces for this particular problem is because most of the times you're going to extend and reuse simple/common confirmation dialogs like that. hey are too generic to be "wasted" (or worse: duplicated if different event actions arise).
Unless you are deadly sure that you are going to use that only once, for one purpose (finishing), you generally should avoid hardwiring (and simplifying) the implementation details of the Activity
in your dialog class. Flexibility, abstraction and efficiency. Less code to maintain.
And yes, there is a telltale that you may need that: the public
keyword that you're using, especially if it's in a self-contained class file, which begs for reuse (too). Otherwise, you should be hiding that class inside your main Activity
, since the implementation details (would) relate only to that one. Also, you would be removing the public
keyword.
Yes, you could use for more than one Activity
, but you'd be limited to finish()
ing. The interface will give you flexibility to do whatever you want in each Activity
. In other words, it's up to the implementer to define how it should itself behave for that event. You self-contain implementation details.
As a sidenote, what I do is create a package with all dialogs I may need for my application. For confirmation dialogs like that, I reuse for different messages and buttons. I provide defaults, but also allow for change using setArguments
. And I keep the interfaces related so I don't need to create one interface for each dialog. The implementer responds according to which dialog triggered the "dialogs callback". Flexibility, abstraction and efficiency, all while avoiding things humorously called Hydra and Royal Family. So. In the end, like I said, many options. Don't over-engineer, but don't simplify too much too early (leave room for graceful expansion).
It's more important to understand advantages and pitfalls than choosing this or the other answer.
回答2:
Even though the amount of work involved to make the interface is small, I don't see why you need to call finish()
from the Activity that created it. Calling finish()
from within the DialogFragment itself will suffice. If you need to send info back with it as well for some reason, you could always call getActivity()
and chain a method that exists in the Activity. Ultimately no matter where you call finish, it will detach the Fragment and destroy it.
Just to clarify how to call a method from your Activity in your Fragment
((YourActivity)getActivity()).someMethod(param);
You MUST caste it because Java doesn't know that Activity has whatever method you wanna call. Which ever way you decide to go with, good luck :)
cheers
EDIT
I appreciate your clarification David. In general you are correct. But to be honest in this instance, you are incorrect because of the nature of Fragments and their relationships with the Activity. Again, you will essentially be creating a listener in order to be called by a Fragment that already has an extremely close relationship with the Activity class it is being held by. Any benefits provided by not hardwiring anything through listeners is lost in this case. You will still be rewriting custom code for every Dialog. While in my method you can write a method in the Activity class in such a general way that you only ever have to write it once.
There are only two reasons I see a need to use a Listener:
1. If you are writing code that other people will be using. So you provide an easy way to give info while maintaining a certain structure (like Androids DatePickerDialog).
2. If there is no connection between two parts you are trying to maintain connected (like GUI's in Java).
So I am not trying to say that David is wrong in saying this, and I am grateful he is bringing it up because it is important for people to understand when to use them. But again, in this case the benefits he mentions are non-existent due to the connection between Fragments and the Activity class. Just wanted to clarify why I believe listeners are not necessary here.
回答3:
Instead of:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
Use:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// this gets the current activity.
Activity currentActivity = getActivity();
// this finish() method ends the current activity.
currentActivity.finish();
}
})
来源:https://stackoverflow.com/questions/13338113/managing-activity-from-dialogfragment