Fragment中调用getSupportFragmentManager()显示Dialog失败问题
Android Fragment内DialogFragment显示异常修复方案
问题描述
主Activity为带TabLayout和ViewPager的仪表盘,菜单点击功能正常,但Fragment内调用DialogFragment时出现异常,相同代码在普通Activity中可正常运行,尝试多种论坛方案未解决。
相关代码
ScanTabFragment代码
import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; public class ScanTabFragment extends Fragment implements View.OnClickListener, ProjectDialogActivity.DialogListener{ private CardView cardViewCreateProjectBatch; private View view; private DatabaseHelperBatch mySQLiteAdapterBatch; // 补充声明变量 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_scan_tab, container, false); cardViewCreateProjectBatch = view.findViewById(R.id.cardViewCreateProjectBatch); cardViewCreateProjectBatch.setOnClickListener(this); return view; } @Override public void onClick(View view) { switch (view.getId()) { case R.id.cardViewCreateProjectBatch: newProjectDialog(); break; } } private void newProjectDialog() { String projectNameAuto = "PJ-Batch-" + android.text.format.DateFormat.format("yyyy.MM.dd.kk.mm.ss", new java.util.Date()); FragmentManager fm = getSupportFragmentManager(); // 此处获取方式错误 // 尝试过的错误写法 //FragmentManager fm = getActivity().getSupportFragmentManager(); //FragmentManager fm = this.getParentFragment().getChildFragmentManager(); //FragmentManager fm = this.getParentFragment().getFragmentManager(); //FragmentManager fm = this.getParentFragment().getFragmentManager().beginTransaction(); //FragmentManager fm = this.getChildFragmentManager(); //FragmentManager fm = getFragmentManager(); //FragmentManager fm = getParentFragment(); ProjectDialogActivity alertDialog = ProjectDialogActivity.newInstance("Create New Batch Project", projectNameAuto, ""); alertDialog.setCancelable(false); alertDialog.show(fm, "fragment_alert"); // 重复创建Dialog实例 ProjectDialogActivity alertDialog = ProjectDialogActivity.newInstance("Create New Batch Project", projectNameAuto, ""); alertDialog.setCancelable(false); alertDialog.show(fm, "fragment_alert"); } public long insertProject1(String project_name, String created_date, Integer status, String notes) { mySQLiteAdapterBatch = new DatabaseHelperBatch(view.getContext()); SQLiteDatabase db = mySQLiteAdapterBatch.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("project_name", project_name); contentValues.put("created_date", created_date); contentValues.put("status", status); contentValues.put("notes", notes); return db.insert("project1", null, contentValues); } public long insertProject2(String project_name, String created_date, Integer status, String notes) { mySQLiteAdapterBatch = new DatabaseHelperBatch(view.getContext()); SQLiteDatabase db = mySQLiteAdapterBatch.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("project_name", project_name); contentValues.put("created_date", created_date); contentValues.put("status", status); contentValues.put("notes", notes); return db.insert("project2", null, contentValues); } @Override public void applyTexts(String project_name, String created_date, Integer status, String notes) { if (ProjectDialogActivity.radioButtonProject1.isChecked() == true) { insertProject1(project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project1 has been created", Toast.LENGTH_LONG).show(); } if (ProjectDialogActivity.radioButtonProject2.isChecked() == true) { insertProject2(project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project2 has been created", Toast.LENGTH_LONG).show(); } } }
ProjectDialogActivity(DialogFragment)代码
import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.RadioButton; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDialogFragment; import java.util.Calendar; public class ProjectDialogActivity extends AppCompatDialogFragment { private String projectName; private String projectCreated; private String projectNotes; private Integer projectStatus; private TextView textViewProjectName; private TextView textViewNotes; public static RadioButton radioButtonProject1; // 静态变量存在风险 public static RadioButton radioButtonProject2; public static ProjectDialogActivity newInstance(String title, String getProjectName, String getNotes) { ProjectDialogActivity frag = new ProjectDialogActivity(); Bundle args = new Bundle(); args.putString("title", title); args.putString("inputProjectName", getProjectName); args.putString("inputNotes", getNotes); frag.setArguments(args); return frag; } private DialogListener listener; @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { String title = getArguments().getString("title"); String inputProjectName = getArguments().getString("inputProjectName"); String inputNotes = getArguments().getString("inputNotes"); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); final View view = inflater.inflate(R.layout.activity_projectdialog, null); radioButtonProject1 = view.findViewById(R.id.radioButtonScan1); radioButtonProject2 = view.findViewById(R.id.radioButtonScan2); textViewProjectName = view.findViewById(R.id.editTextProjectName); textViewNotes = view.findViewById(R.id.editTextNotes); textViewProjectName.setSingleLine(true); textViewNotes.setSingleLine(true); textViewProjectName.setText(inputProjectName); textViewNotes.setText(inputNotes); projectName = textViewProjectName.getText().toString(); builder.setView(view) .setTitle(title) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialoginterface, int i) { dialoginterface.cancel(); } }) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); return builder.create(); } @Override public void onResume() { super.onResume(); final AlertDialog d = (AlertDialog) getDialog(); if (d != null) { Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE); positiveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { projectName = textViewProjectName.getText().toString(); projectCreated = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime()); projectStatus = 0; projectNotes = textViewNotes.getText().toString(); Boolean wantToCloseDialog; if (projectName.isEmpty()) { Toast.makeText(getContext(), "Cannot left blank, Please input your project name", Toast.LENGTH_LONG).show(); textViewProjectName.requestFocus(); wantToCloseDialog = false; } else { wantToCloseDialog = true; } if (wantToCloseDialog == true) { listener.applyTexts(projectName, projectCreated, projectStatus, projectNotes); d.dismiss(); } } }); } } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); try { listener = (DialogListener) context; // 绑定到Activity,而非Fragment } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement DialogListener"); } } public interface DialogListener { void applyTexts(String project_name, String created_date, Integer status, String Notes); } }
修复步骤
1. 修正FragmentManager获取方式
在ScanTabFragment的newProjectDialog()方法中,使用getChildFragmentManager()获取FragmentManager,用于管理当前Fragment的子DialogFragment:
private void newProjectDialog() { String projectNameAuto = "PJ-Batch-" + android.text.format.DateFormat.format("yyyy.MM.dd.kk.mm.ss", new java.util.Date()); FragmentManager fm = getChildFragmentManager(); // 正确获取方式 ProjectDialogActivity alertDialog = ProjectDialogActivity.newInstance("Create New Batch Project", projectNameAuto, ""); alertDialog.setCancelable(false); alertDialog.show(fm, "fragment_alert"); }
同时删除重复创建Dialog的代码段。
2. 修复DialogListener绑定逻辑
修改ProjectDialogActivity的onAttach方法,优先从父Fragment获取Listener,确保实现了接口的Fragment能接收回调:
@Override public void onAttach(@NonNull Context context) { super.onAttach(context); if (getParentFragment() instanceof DialogListener) { listener = (DialogListener) getParentFragment(); } else if (context instanceof DialogListener) { listener = (DialogListener) context; } else { throw new ClassCastException(context.toString() + " 必须实现DialogListener"); } }
3. 移除静态RadioButton,传递选中状态
- 去掉
radioButtonProject1和radioButtonProject2的static修饰符 - 更新
DialogListener接口,添加选中状态参数:
public interface DialogListener { void applyTexts(String project_name, String created_date, Integer status, String Notes, boolean isProject1Checked); }
- 修改
ProjectDialogActivity的onResume方法,传递选中状态:
if (wantToCloseDialog == true) { boolean isProject1Checked = radioButtonProject1.isChecked(); listener.applyTexts(projectName, projectCreated, projectStatus, projectNotes, isProject1Checked); d.dismiss(); }
- 在
ScanTabFragment中更新applyTexts实现:
@Override public void applyTexts(String project_name, String created_date, Integer status, String notes, boolean isProject1Checked) { if (isProject1Checked) { insertProject1(project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project1 has been created", Toast.LENGTH_LONG).show(); } else { insertProject2(project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project2 has been created", Toast.LENGTH_LONG).show(); } }
4. 优化数据库重复代码
合并insertProject1和insertProject2为一个通用方法:
public long insertProject(String tableName, String project_name, String created_date, Integer status, String notes) { mySQLiteAdapterBatch = new DatabaseHelperBatch(view.getContext()); SQLiteDatabase db = mySQLiteAdapterBatch.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("project_name", project_name); contentValues.put("created_date", created_date); contentValues.put("status", status); contentValues.put("notes", notes); return db.insert(tableName, null, contentValues); }
然后在applyTexts中调用:
if (isProject1Checked) { insertProject("project1", project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project1 has been created", Toast.LENGTH_LONG).show(); } else { insertProject("project2", project_name, created_date, status, notes); Toast.makeText(view.getContext(), "New Batch project2 has been created", Toast.LENGTH_LONG).show(); }
内容的提问来源于stack exchange,提问作者ed ed
相关产品推荐
相关产品推荐

