【问题标题】:Callback function did't trigger when calling from DialogFragment to Fragment从 DialogFragment 调用到 Fragment 时没有触发回调函数
【发布时间】:2016-10-30 08:04:05
【问题描述】:

现在我有:-

1) 1 Activity,它是从AppCompactActivity延伸出来的主要Activity。

2) 1 fragment 扩展自 fragment 的类,这是从主要活动调用的片段 (1) - ProfileTeacherActivity.java

3) 1 从DialogFragment 扩展的片段类,从片段(2) - ModalBox.java

调用此对话框

所以,基本上,这只是一个简单的执行流程。开始时,应用程序显示main activity (1) 具有抽屉,其中有几个链接作为配置文件链接的示例,当单击此链接时,应用程序调用fragment (2) 显示配置文件的详细信息,并带有一个编辑按钮。单击编辑按钮后,应用程序将调用包含一些EditText 的DialogFragment (3) 来编辑用户的配置文件。

我想要实现的是,在编辑用户的个人资料并成功保存到数据库后,我尝试将用户的数据发送回fragment (2) 只是为了显示最新的更新信息,不幸的是它没有工作。

这是我尝试过的:

1) 在 DialogFragment 中创建接口 (3) - ModalBox.java

public class ModalBox extends DialogFragment{

   ....
   public interface EditProfileModalBoxInterface {
     void onFinishEditProfile( HashMap<String, String> dataPassing );
   }
   ...
   ...
}

2) 在 DialogFragment 内部,我还为 OK 按钮提供了 .setPositiveButton 函数。 - ModalBox.java

public class ModalBox extends DialogFragment{
   ...       
   ...
   public Dialog onCreateDialog(Bundle savedInstanceState ) {
      ...
      builder
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(final DialogInterface dialog, int id) {
               // At here i'm using retrofit2 http library
               // to do updating stuff
               // and inside success's callback of retrofit2(asynchronous)
               // here i call the below function to send data 
               // dataToSend is a HashMap value
               sendBackResultToParent( dataTosend );
            }
        })
         .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                // User cancelled the dialog
            }
        });
      .....
   }

   // Function called inside success's callback of retrofit2
   public void sendBackResultToParent( HashMap<String, String> data ) {
      // instantiated interface
      EditProfileModalBoxInterface ls=(EditProfileModalBoxInterface)getTargetFragment();
      // declaring interface's method
      ls.onFinishEditProfile( data );
   }
}

3) 最后,我在 fragment 内部实现了这些接口 (2) - ProfileTeacherActivity.java

public class ProfileTeacherActivity extends Fragment 
       implements ModalBox.EditProfileModalBoxInterface{

    public View onCreateView(LayoutInflater inflater, 
                   ViewGroup container, Bundle savedInstanceState ) {
       .....
       .....
    }

    // At here the interface's method did't triggered
    @Override
    public void onFinishEditProfile( HashMap dataPassedFromDialog ) {
      Toast.makeText(getActivity(), "Testing...." , Toast.LENGTH_LONG).show();
    }

}

我现在感到困惑的是,只有当我在 retrofit2 成功的回调中调用此函数 sendBackResultToParent( dataTosend ); 时才会出现问题,在它之外调用时会触发它。我假设调用的异步导致了这个。如果我可以使用 Promise 或类似的东西,或者有什么解决方法吗?

以下现有解决方案不适用于我的情况:

如果上述用例不够清楚或存在误解,请向我咨询更多意见。感谢您的帮助。问候。

【问题讨论】:

  • 不相关,但将片段命名为“ProfileTeacherActivity”有点误导。 :)
  • @TalhaMir 是的,这是我的愚蠢错误。 ;)

标签: java android android-fragments android-dialogfragment asynccallback


【解决方案1】:

罪魁祸首终于找到了。上面提到的所有答案都是正确的。而且我的脚本实际上也可以工作,问题与我的 API json's 响应有关,该响应没有正确的结构。就我而言,我使用retrofit2 和GSON 转换器来解析为POJO。发现日志上的信息说:

预期为 BEGIN_OBJECT,但为 BEGIN_ARRAY

意味着,GSON 期待 json object,这是我的 API,返回了 JSON array。只需更改 API 的结构,然后所有商品都可以使用。谢谢大家辛苦了。真的很感激,因为我现在知道如何处理eventBus,替换默认的OK 和Cancel 按钮以及片段之间通信的正确方式。

【讨论】:

  • 是的,始终保持您的改造登录。不要忘记使用 Dagger2。还可以考虑使用 RxJava 进行改造。最好的。
【解决方案2】:

从架构的角度来看,2 个片段不应该直接相互通信。容器活动应该负责在它的子片段之间传递数据。所以我会这样做:

在容器 Activity 中实现您的接口,只需将您在 Activity 中的接口实现附加到 Dialog 类,并在需要时调用该接口方法。像这样的:

    public static class ModalBox extends DialogFragment {

    EditProfileModalBoxInterface mListener;

    // Container Activity must implement this interface
    public interface EditProfileModalBoxInterface {
     void onFinishEditProfile( HashMap<String, String> dataPassing );
   }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (EditProfileModalBoxInterface) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement EditProfileModalBoxInterface");
        }
    }
}

然后在DialogFragment 类中需要的地方调用mListener.onFinishEditProfile(....)。

这样,您将在 Activity 类中接收返回结果,您可以从该类中调用所需片段的相关方法以将结果传递给该片段。

整个流程已被描述here

【讨论】:

  • 看起来我现在使用了错误的概念,让两个片段相互通信。所以,即使我使用eventBus 就像其他人的答案一样,它是否无效或不推荐?
  • @NorlihazmeyGhazali Otto 也可以。我用它所有的时间。这是一个方便的图书馆。只是想解释一下谷歌官方是如何推荐它的。但是使用 EventBus 也完全可以解决这个问题。
  • 感谢您的澄清。我直接在两个片段之间进行通信,因为想要避免搞乱主要活动,因为我还有另一个片段要处理。无论如何,如果我在改造的异步成功回调外部调用mListener.onFinishEditProfile(....),这种方式确实有效,不幸的是在内部调用时不起作用。太奇怪了。
【解决方案3】:

这是一个示例DialogFragment 代码,用于向选定的联系人发送消息。我也需要捕获DialogFragment 上的点击事件并重定向。

理想情况下,这是需要做的

  • 覆盖AlertDialog.Builder 的正/负按钮点击并且不执行任何操作
  • 在此之后,使用getButton 方法提及AlertDialog.BUTTON_NEGATIVE 或AlertDialog.BUTTON_POSITIVE 并指定一个操作

public class SMSDialogFrag extends DialogFragment {

    private static String one="one";
    private EditText messageContent;
    private AlertDialog dialog;
    private String mobNumber;

    public static SMSDialogFrag showDialog(String mobNumber){
        SMSDialogFrag customDialogFrag=new SMSDialogFrag();
        Bundle bundle=new Bundle();
        bundle.putString(one, mobNumber);
        customDialogFrag.setArguments(bundle);
        return customDialogFrag;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
        View view = getActivity().getLayoutInflater().inflate(R.layout.sms_dialog, null);

        alertDialogBuilder.setView(view);
        setupUI(view);
        alertDialogBuilder.setTitle("");

        alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //Do nothing here because we override this button later
            }
        });
        alertDialogBuilder.setPositiveButton("Send", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //Do nothing here because we override this button later
            }
        });
        dialog = alertDialogBuilder.create();
        dialog.show();
        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
                //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
            }
        });
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendMessage();//IN YOUR USE CASE YOU CAN REDIRECT TO YOUR CALLER FRAGMENT

            }
        });

        return dialog;
    }
    void setupUI(View view){
        TextView textViewMob=(TextView)view.findViewById(R.id.mobNumber);
        messageContent=(EditText)view.findViewById(R.id.messageContent);
        mobNumber=getArguments().getString(one);
        textViewMob.setText("Send message to : "+mobNumber);
    }
    void sendMessage(){
        if( ! TextUtils.isEmpty(messageContent.getText())){
            try {
                SmsManager smsManager = SmsManager.getDefault();
                Log.v(Constants.UI_LOG,"Number >>>>>>> "+mobNumber);
                smsManager.sendTextMessage(mobNumber, null, messageContent.getText().toString(), null, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Toast.makeText(getActivity(),"Message Sent!",Toast.LENGTH_SHORT).show();
            dialog.dismiss();
        }else{
            Toast.makeText(getActivity(),"Please enter message to send!",Toast.LENGTH_SHORT).show();
        }
    }
}

【讨论】:

  • 不错的解决方案,但是如果我们替换 OK 和 Cancel 按钮的默认操作是否有任何错误或误用?
  • @NorlihazmeyGhazali:我没有找到。或许你可以尝试实施和交叉检查
【解决方案4】:

考虑使用 eventBus,例如 Otto

用法很简单。您需要做的就是创建一个 evenbus:

public static Bus bus = new Bus(ThreadEnforcer.MAIN);  //use Dagger2 to avoid static

然后创建一个接收器方法(在您的情况下为片段 2):

@Subscribe
public void getMessage(String s) {
  Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}

通过调用(来自 DialigFramgent)向您发送消息:

bus.post("Hello");

并且不要忘记在 onCreate 方法(您的 Fragment)中注册您的 eventBus:

bus.register(this);

就是这样!

【讨论】:

  • 如果我在成功回调中调用bus.post("Hello");,订阅者的事件永远不会触发。当我在成功的回调外部调用时,它会触发。
猜你喜欢
  • 2013-10-15
  • 1970-01-01
  • 2013-01-16
  • 2014-11-11
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多