多个活动/片段的自定义对话框界面

时间:2018-06-20 16:24:56

标签: java android android-studio android-fragments dialog

我是android studio的新手,我试图实现一个dialogfragment,以便在单击按钮或单击工具栏action_add按钮时弹出。它将数据从对话框发送到片段或活动(试图了解它们如何对两者起作用)。我的对话框类有一个接口,当我在片段中实现它时,该接口工作得很好,但是活动有些不同。我正在使用接口将数据传递给活动,然后正在使用Bundle将数据从活动传递到片段。我相信错误发生在onAttach中,因为我有getTargetFragment();。

是否可以让多个活动/片段实现一个接口?如果是这样,我该如何兼顾接口onAttach和数据发送中的活动和片段?

在此先感谢大家,以下是该对话框的custom_dialog类的代码以及与活动相关的一个片段。目标是按下片段中的按钮或活动上的工具栏以打开对话框并从用户那里获得输入,该输入将被转移以显示。

错误:

Process: com.example.andrewg.dialogfragment, PID: 13335
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.andrewg.dialogfragment.MyCustomDialog$OnInputSelected.sendInput(java.lang.String)' on a null object reference
    at com.example.andrewg.dialogfragment.MyCustomDialog$2.onClick(MyCustomDialog.java:58)
    at android.view.View.performClick(View.java:6597)
    at android.view.View.performClickInternal(View.java:6574)
    at android.view.View.access$3100(View.java:778)
    at android.view.View$PerformClick.run(View.java:25881)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6649)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)

MainActivity:

public class MainActivity extends AppCompatActivity implements 
MyCustomDialog.OnInputSelected{

public String dialogInput;
FragmentManager fragmentManager;

@Override
public void sendInput(String input) {
    dialogInput = input;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    fragmentManager = getSupportFragmentManager();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    //Inflate the menu, this adds items to the action bar if it is present
    getMenuInflater().inflate(R.menu.menu, menu);

    //Redundant
    MenuItem actionMenuItem = menu.findItem(R.id.action_add);
    actionMenuItem.setOnMenuItemClickListener(new 
MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            return false;
        }
    });
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    //Handle action bar clicks here. The action bar will automatically handle clicks on the home/up button
    //so long as you specify a parent activity in AndroidManifest.xml

    switch(item.getItemId()){

        case R.id.action_add:
            MyCustomDialog dialog = new MyCustomDialog();
            dialog.show(getSupportFragmentManager(), "MyCustomDialog");

            //Trying to pass dialog input into an intent to send to the 
fragment
            /*Intent intent = new Intent(getApplicationContext(), 
MainFragment.class);
            intent.putExtra("Dialog Input", dialogInput);
            startActivity(intent);*/
            //Trying Bundle to pass data, dialog input between activity and 
fragment
            Bundle bundle = new Bundle();
            bundle.putString("Dialog Input", dialogInput);
            //Set Fragment class arguments
            MainFragment fragment = new MainFragment();
            fragment.setArguments(bundle); //set argument bundle to fragment

            fragmentManager.beginTransaction().replace(R.id.MainFragment,fragment).commit(); //now replace Mainfragment


            Toast.makeText(this, "Action_Add Clicked Successfully", 
Toast.LENGTH_SHORT).show();
    }

    return super.onOptionsItemSelected(item);
}
}

MainFragment:

public class MainFragment extends Fragment implements 
MyCustomDialog.OnInputSelected{

TextView InputDisplay;
Button OpenDialog;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, container, false);

    InputDisplay = view.findViewById(R.id.InputDisplay);
    OpenDialog = view.findViewById(R.id.Open_Dialog);

    //Getting Main Activity dialog information with Bundle, that was received from toolbar add
    Bundle bundle = getArguments();
    if(bundle != null){
        String dialogInput = bundle.toString();
        InputDisplay.setText(dialogInput);
    }
    //String dialogInput = this.getArguments().getString("Dialog Input");

    OpenDialog.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("MainFragment", "onClick: opening dialog");

            MyCustomDialog customDialog = new MyCustomDialog();
            customDialog.setTargetFragment(MainFragment.this, 1);
            customDialog.show(getFragmentManager(), "MyCustomDialog");
        }
    });

    return view;
}

@Override
public void sendInput(String input) {
    InputDisplay.setText(input);
}
}

自定义对话框:我为onAttach的活动添加了第二个接口变量,以使用getActivity(),但这似乎不合适。

public class MyCustomDialog extends DialogFragment {

private EditText Input;
private TextView ActionOK, ActionCANCEL;

public OnInputSelected onInputSelected_Fragment;
public OnInputSelected onInputSelected_Activity;

public interface OnInputSelected{
    void sendInput(String input);
}

@Override
public void onAttach(Context context) {
    try{
        onInputSelected_Fragment = (OnInputSelected) getTargetFragment();
        onInputSelected_Activity = (OnInputSelected) getActivity();
    }catch(ClassCastException e){
        Log.e("Custom Dialog", "onAttach: ClassCastException: " + e.getMessage());
    }
    super.onAttach(context);
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.dialog_my_custom, container, false);

    Input = view.findViewById(R.id.Input);
    ActionOK = view.findViewById(R.id.Action_OK);
    ActionCANCEL = view.findViewById(R.id.Action_CANCEL);

    ActionCANCEL.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            getDialog().dismiss();
        }
    });

    ActionOK.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            onInputSelected_Fragment.sendInput(Input.getText().toString());
            onInputSelected_Activity.sendInput(Input.getText().toString());

            getDialog().dismiss();
        }
    });

    return view;
}
}

2 个答案:

答案 0 :(得分:1)

  

是否可以有多个活动/片段实现一个接口?

是的。您只需要知道,如果getActivity()未附加到null而是附加到另一个DialogFragmentActivity上,则Fragment将返回getTargetFragment()如果没有目标null,将返回Fragment,例如当您直接从Activity中显示对话框时,因此没有调用setTargetFragment()

由于将null强制转换为任何值都不会导致Exception,因此您在代码中要做的就是在实际调用接口方法之前进行null检查。

但是由于您将没有目标FragmentActivity来显示DialogFragment的相同实例,因此您可以更改代码并只处理一个字段

private OnInputSelected onInputSelected;

然后在onAttach()中检查哪个为空-Activity或目标Fragment-并一劳永逸地正确设置onInputSelected

try{
    Fragment onInputSelected_Fragment = getTargetFragment();
    Activity onInputSelected_Activity = getActivity();
    if (onInputSelected_Fragment != null){
        onInputSelected = (OnInputSelected)onInputSelected_Fragment;
    }
    else {
        onInputSelected = (OnInputSelected)onInputSelected_Activity;
    }
    // throw RuntimeException here if onInputSelected still is null
    //
}catch(ClassCastException e){
    Log.e("Custom Dialog", "onAttach: ClassCastException: " + e.getMessage());
}

请注意,如果从片段显示对话框时忘记设置目标onInputSelected,则Fragment可能为空。这将是编程错误,因此在这种情况下,您可能想抛出RuntimeException。如果您的应用超出了这一点,则说明您已经实现了界面,任务得以完成。

在您的onClick()中,您只需编写即可

onInputSelected.sendInput(Input.getText().toString());

答案 1 :(得分:0)

getActivity()返回null。根据{{​​3}},在运行onAttach之后,getActivity()将返回null。如果将super.onAttach()移到onAttach方法的开头,则它应正确返回活动。

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    try{
        onInputSelected_Fragment = (OnInputSelected) getTargetFragment();
        onInputSelected_Activity = (OnInputSelected) getActivity();
    }catch(ClassCastException e){
        Log.e("Custom Dialog", "onAttach: ClassCastException: " + e.getMessage());
    }

}