简体   繁体   English

Android:将对话框按钮与活动连接的正确方法是什么?

[英]Android: What is the proper way of connecting dialog buttons with an activity?

Here is what I would like to do: 这是我想做的:

1) Inside an Activity a dialog is shown. 1)在Activity内将显示一个对话框。 I use DialogFragment and FragmentManager for this, by calling: 为此,我使用DialogFragmentFragmentManager ,方法是:

dialogFragment.show(fragmentManager, "edit_task_list");

2) Inside the Dialog I have layout with a custom Button . 2)在Dialog我有一个带有自定义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 . 1) Button onclick属性以及Actvity的方法。 That was my original plan, but I don't how to get the Dialog from the Activity to dismiss it. 那是我最初的计划,但是我不知道如何从Activity获取Dialog以将其关闭。 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 . 2)在DialogFragment创建Dialog时,在按钮上的单击侦听器上进行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). 这将需要我将一些上下文从Activity传递到DialogFragment ,所以我想避免这种情况(并保持DialogFragment尽可能简单)。

Which of those options should I take? 我应该选择哪些选项?

Number 2 Doesn't require you to pass any context (and you shouldn't). 2号不需要您传递任何上下文(也不应该)。 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): 在对话框和button.onClick()中,您可以执行以下操作(未经测试的代码):

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. 所有Activity和Fragment类都有一个内置的回调方法,供您在启动另一个Activity,Fragment,Dialog或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. 由于要从活动启动对话框,因此使用Dialog类比DialogFragment类更好。 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() ) 后者更适合从Fragment启动对话框,因为它有两种方法可以与Fragment通信( get/set TargetFragment() )。

The Dialog class has the getOwnerActivity() method. Dialog类具有getOwnerActivity()方法。 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. 您可以在Dialog类的按钮上设置onClickListener。 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. 您将其他要发送的信息放入了Intent中。

1) onclick attribute in the Button and a method inside the Actvity. 1)Button中的onclick属性以及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; 基本上,您的Activity必须使用curDialog=dialogFragment;类的curDialog=dialogFragment;来记住/知道当前哪个对话框处于活动状态curDialog=dialogFragment; , then when handling the button onclick action you'll know which dialog to dismiss. ,然后在处理按钮onclick动作时,您将知道要关闭哪个对话框。 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. 但这并不是一个好主意,因为基本上按钮视图会从DialogFragment泄漏到Activity,从而破坏对象封装。

2) set on click listener on the button when the Dialog is created in DialogFragment. 2)在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). 这将需要我将一些上下文从Activity传递到DialogFragment,所以我想避免这种情况(并保持DialogFragment尽可能简单)。

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() . 作为前面提到的答案,您不需要将任何Context传递给它,尤其是因为您可以通过调用getActivity()获得Activity。

The solution depends on whether or not this dialog would be used by multiple Activities: 解决方案取决于多个活动是否使用此对话框:

  1. Used by a single Activity: @Martin's solution will work just fine 由单个活动使用:@Martin的解决方案可以正常工作
  2. Used by multiple Activity: abstraction can be used such that only the user's decision is passed to a listener. 由多个Activity使用:可以使用抽象,以便仅将用户的决定传递给侦听器。 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. 因此,如果上面的type值设置为115,则单击dialogYes会触发以115true作为第一和第二参数调用public void onSelect(int type, boolean yes)方法。

Your first point about the onClick attribute in the xml should be avoided. 应该避免有关xml中的onClick属性的第一点。 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.show(fragmentManager, "edit_task_list");设置的标签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. 正确的解决方案是使用接口作为DialogFragment与Activity之间的通信的回调。 This keeps the Dialog modular and the code easy. 这样可以使Dialog保持模块化且代码容易。 Here is an example from the docs . 这是docs中的示例。 For this you don't need a Context. 为此,您不需要上下文。 You simply pass the interface to the dialog in the onAttach() callback. 您只需在onAttach()回调中将接口传递给对话框onAttach() It has a reference of the Activity as a parameter, which called that Dialog. 它具有对Activity的引用作为参数,称为该对话框。

// 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. 处理对话框中的“按钮”单击,然后在其中调用dismiss(),以使对话框可以自行关闭。 Have a look at this question why to use dismiss() instead of getDialog().dismiss(). 看一下这个问题,为什么要使用dismiss()而不是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. 在对话框的onPause()中,将接口的引用设置为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. 我不知道您的总体设置,但是如果您要使用AlertDialog,则在该方法返回时,单击Button会自动关闭该对话框。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Android Studio 按钮没有将我重定向到正确的活动 - Android Studio buttons not redirecting me to the proper activity Android:后台的按钮“对话框”的活动处于活动状态? - Android : Buttons in the background Activity of a 'Dialog' is active? 取消注册Activity生命周期回调的正确方法是什么? - What is the proper way to unregister Activity lifecycle callbacks? 从服务关闭活动的正确方法是什么? - What is the proper way to close an Activity from a Service? 在Activity和BroadcastReceiver之间进行通信的正确方法是什么? - What is the proper way to communicate between an Activity and a BroadcastReceiver? 在Android中关闭/完成活动的正确方法 - Proper way to close/finish Activity in Android Android:从支持库向“工具栏”小部件添加操作按钮的正确方法是什么? - Android: What is the proper way to add action buttons to the Toolbar widget from the Support Library? 在所有“活动”按钮上设置setOnClickListener()的简单方法是什么 - What is the easy way to setOnClickListener() on all Activity Buttons 在Dialog的ListView中获取任何项目的视图的正确方法是什么 - What is the proper way to get a view of any item in ListView in Dialog 正确使用单一登录并避免额外对话框的方法(Android) - Proper Way To Use Single Sign On And Avoid Extra Dialog (Android)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM