问题
I have problem with Dialog
fragment. Simple dialog with my custom layout is working ok. But I want to initiate controls when dialog is showing. I'm trying to do this in method onActivityCreated
. But getView()
return null, so I thought that I must set my custom view in onCreateView
instead of onCreateDialog
. And here the error occurs. When I use onCreateView then my application crashes. Here is my code:
class StatisticDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder .setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// FIRE ZE MISSILES!
}
});
// Create the AlertDialog object and return it
return builder.create();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.statistics, container, true);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
}
I open this dialog on button click on activity:
StatisticDialog dlg = new StatisticDialog();
dlg.show(getSupportFragmentManager(), "missiles");
And errors:
11-08 18:05:14.470: E/AndroidRuntime(1075): FATAL EXCEPTION: main
11-08 18:05:14.470: E/AndroidRuntime(1075): android.util.AndroidRuntimeException: requestFeature() must be called before adding content
11-08 18:05:14.470: E/AndroidRuntime(1075): at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:215)
11-08 18:05:14.470: E/AndroidRuntime(1075): at com.android.internal.app.AlertController.installContent(AlertController.java:234)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.app.AlertDialog.onCreate(AlertDialog.java:336)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.app.Dialog.dispatchOnCreate(Dialog.java:351)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.app.Dialog.show(Dialog.java:256)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.DialogFragment.onStart(DialogFragment.java:385)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.Fragment.performStart(Fragment.java:1336)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:907)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1083)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:635)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1431)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.os.Handler.handleCallback(Handler.java:615)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.os.Handler.dispatchMessage(Handler.java:92)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.os.Looper.loop(Looper.java:137)
11-08 18:05:14.470: E/AndroidRuntime(1075): at android.app.ActivityThread.main(ActivityThread.java:4745)
11-08 18:05:14.470: E/AndroidRuntime(1075): at java.lang.reflect.Method.invokeNative(Native Method)
11-08 18:05:14.470: E/AndroidRuntime(1075): at java.lang.reflect.Method.invoke(Method.java:511)
11-08 18:05:14.470: E/AndroidRuntime(1075): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
11-08 18:05:14.470: E/AndroidRuntime(1075): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
11-08 18:05:14.470: E/AndroidRuntime(1075): at dalvik.system.NativeStart.main(Native Method)
回答1:
try this:
class StatisticDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.statistics, null);
builder.setView(view);
builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// FIRE ZE MISSILES!
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
回答2:
Avoid request feature crash:
public class MyCombinedFragment extends DialogFragment { private boolean isModal = false;
public static MyCombinedFragment newInstance()
{
MyCombinedFragment frag = new MyCombinedFragment();
frag.isModal = true; // WHEN FRAGMENT IS CALLED AS A DIALOG SET FLAG
return frag;
}
public MyCombinedFragment()
{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(isModal) // AVOID REQUEST FEATURE CRASH
{
return super.onCreateView(inflater, container, savedInstanceState);
}
else
{
View view = inflater.inflate(R.layout.fragment_layout, container, false);
setupUI(view);
return view;
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder alertDialogBuilder = null;
alertDialogBuilder = new AlertDialog.Builder(getActivity());
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_layout, null);
alertDialogBuilder.setView(view);
alertDialogBuilder.setTitle(“Modal Dialog“);
alertDialogBuilder.setPositiveButton("Cancel", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
});
setupUI(view);
return alertDialogBuilder.create();
}
}
回答3:
you should use DialogFragment that is flexible to set it any layout. you should follow this steps. perhaps it is complicated but very strong and flexible. the more important things is your Activity getting Date from Dialogfragment.
1- Create a class of instance to listen and get date from your dialogfragment from your activity.I named it as OnMFDialogFragmentDoneListener.java.
2-create your DialogFragment and define your layout in onCreateView method and 3-use your class and new methods in your activity
I create a DialogFragment to get user name and password form user and delivers this date to activity.Dialog fragment contains a textview, two EditText and two buttons(Logon and cancel. but you can use anythings.
step 1: OnMFDialogFragmentDoneListener.java
public interface OnMFDialogFragmentDoneListener {
public void onMFDialogFragmentDone(String tag,boolean cancelled,
CharSequence username,
CharSequence password);
}
the method onMFDialogFragmentDone must be define in DialogFragment class to send info to yor activity and in your activity to get info.(info= the date that user typed in DialogFragmetn like txt or others).
step2 design your DialogFragment class.
public class MFDialogFragment extends DialogFragment
implements View.OnClickListener{
private EditText editTextusername,editTextpassword;
public static MFDialogFragment newInstance(String title){
MFDialogFragment mfDialogFragment=new MFDialogFragment();
Bundle bundle =new Bundle();
bundle.putString("title",title);
mfDialogFragment.setArguments(bundle);
return mfDialogFragment;
}
@Override
public void onAttach(Activity act){
try{
OnMFDialogFragmentDoneListener
test= (OnMFDialogFragmentDoneListener) act;
}catch (ClassCastException cce){
////...activity !!!! not listen to me
}
super.onAttach(act);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
this.setCancelable(true);
int style = DialogFragment.STYLE_NORMAL, theme = 0;
setStyle(style, theme);
}
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle bundle) {
View v = inflater.inflate(R.layout.mfdialogfragmentlayout, container,
false);
TextView tvtitle = (TextView) v.findViewById(R.id.tv_dialogfragmentuserpass_title);
tvtitle.setText(getArguments().getString("title"));
editTextusername = (EditText) v.findViewById(R.id.et_dialogfragmentuserpass_username);
editTextpassword = (EditText) v.findViewById(R.id.et_dialogfragmentuserpass_password);
Button btnlogin = (Button) v.findViewById(R.id.btn_dialogfragmentuserpass_login);
btnlogin.setOnClickListener(this);
Button btncancel = (Button) v.findViewById(R.id.btn_dialogfragmentuserpass_cancel);
btncancel.setOnClickListener(this);
if(bundle!=null) {
editTextpassword.setText(bundle.getCharSequence("SaveInstanceStatepassword"));
editTextusername.setText(bundle.getCharSequence("SaveInstanceStateusername"));
}
return v;
}
@Override
public void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putCharSequence("SaveInstanceStatepassword", editTextpassword.getText());
icicle.putCharSequence("SaveInstanceStateusername", editTextusername.getText());
}
public void onClick(View v)
{
OnMFDialogFragmentDoneListener act = (OnMFDialogFragmentDoneListener)getActivity();
if (v.getId() == R.id.btn_dialogfragmentuserpass_login)
{
act.onMFDialogFragmentDone(this.getTag(), false,
editTextusername.getText(),editTextpassword.getText());
dismiss();
return;
}
if (v.getId() == R.id.btn_dialogfragmentuserpass_cancel)
{
act.onMFDialogFragmentDone(this.getTag(), true, "nousername", "nopass");
dismiss();
return;
}
}
}
step 3- use your DialogFragment in your activity first you add the code "implements OnMFDialogFragmentDoneListener" to your activity class like
public class MainActivity extends Activity
implements OnMFDialogFragmentDoneListener
second
public static final String
PROMPT_MFDIALOGFRAGMENT_TAG="PROMPT_MFDIALOGFRAGMENT_TAG";
third
define the method to get data that inputed to Dialogfragment by
public void onMFDialogFragmentDone(String tag, boolean cancelled,
CharSequence username,
CharSequence password){
String total;
total=username.toString()+"...."+password.toString();
Toast.makeText(this,total,Toast.LengthShort).show();
}
your date are username and password next is define a simple method to call your dialog
public void MFDialogFragmentShow(){
FragmentTransaction ft = getFragmentManager().beginTransaction();
MFDialogFragment mfDialogFragment =
MFDialogFragment.newInstance("Login to your account");
mfDialogFragment.show(ft, PROMPT_MFDIALOGFRAGMENT_TAG);
}
It's done. your frgaments layout mfdialogfragmentlayout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:id="@+id/tv_dialogfragmentuserpass_title"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="User Name"
android:id="@+id/et_dialogfragmentuserpass_username"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Password"
android:password="true"
android:id="@+id/et_dialogfragmentuserpass_password"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login"
android:id="@+id/btn_dialogfragmentuserpass_login"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:id="@+id/btn_dialogfragmentuserpass_cancel"/>
</LinearLayout>
</LinearLayout>
回答4:
There is getShowDialog() method exist in DialogFragment class. Here is an explanation: developer.android.com
if (!getShowsDialog()) {
View rootView = inflater.inflate(R.layout.fr_layout, container, false);
initViews(rootView);
return rootView;
} else {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
来源:https://stackoverflow.com/questions/13294030/dialogfragment-with-a-custom-layout-causes-a-crash-in-my-application