DialogFragment侦听器,用于持续进行配置更改

Ruu*_*kis 7 android dialog android-fragments android-dialogfragment

场景如下,我有一个包含片段的ViewPager,这些片段中的每一个都有一些需要确认的动作.

我继续创建一个DialogFragment,目标是知道如何处理结果的片段,但是在用户确认或拒绝对话之前可能会重新创建片段.

我可以将一个lambda或其他形式的监听器传递给对话框,然后在用户确认对话框时调用它,但问题是如果设备随后被旋转,则lambda会丢失,因为它不能持久化捆绑......

我能想到的唯一方法是将一些UUID分配给对话框,并将应用程序中的UUID连接到lambda,lambda保存在应用程序内的Map上,但这似乎是非常草率的解决方案..

我尝试在线搜索现有的解决方案,例如材料对话框库样本,但大多数情况似乎都忽略了旋转对话框,但这似乎也是一个草率的解决方案,因为对话框可能是较长流程的一部分,例如如

请求购买 - >取消 - >显示带有解释的对话框 - >如果用户想要再次购买

如果我们简单地忽略旋转对话框,那么流动状态将会丢失

und*_*oid 5

如果您传递匿名 lambda/Listener,您将在旋转后丢失它,但如果您让您的活动实现您的侦听器并在onAttach(context)片段方法中分配它,它将在活动重新创建后重新分配。

interface FlowStepListener {
    fun onFirstStepPassed()
    fun onSecondStepPassed()
    fun onThirdStepPassed()
}
Run Code Online (Sandbox Code Playgroud)
class ParentActivity: Activity(), FlowStepListener {
    override fun onFirstStepPassed() {
        //control your fragments here
    }
    override fun onSecondStepPassed() {
        //control your fragments here
    }
    override fun onThirdStepPassed() {
        //control your fragments here
    }
}
Run Code Online (Sandbox Code Playgroud)
open class BaseDialogFragment : DialogFragment() {
    var listener: FlowStepListener? = null

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is FlowStepListener) {
            listener = context
        } else {
            throw RuntimeException("$context must implement FlowStepListener")
        }
    }

    override fun onDetach() {
        super.onDetach()
        listener = null
    }
}
Run Code Online (Sandbox Code Playgroud)


SE *_*lio 0

不要使用回调来捕获对目标对象的引用,而是尝试LocalBroadcastManager文档)。

这种方法的主要优点是:

  1. support-v4您的项目没有额外的依赖项,因为 LocalBroadcastManager 是和/或 AndroidX 的一部分legacy-support-v4,您很可能已经拥有了。

  2. 无需保留任何类型的参考。

简而言之:

  • 在 DialogFragment 中,您不是调用回调,而是Intent通过LocalBroadcastManager和发送带有消息的消息
  • 在您的目标 Fragment 中,您无需将回调传递给 DialogFragment,而是使用 aBroadcastReceiver来侦听来自的消息LocalBroadcastManager

对于从 DialogFragment 内发送:

public static final String MY_ACTION = "DO SOMETHING";

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  final Button button = view.findViewById(R.id.accept);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent broadcastIntent = new Intent(MY_ACTION);
            LocalBroadcastManager.getInstance(getContext()).sendBroadcast(broadcastIntent);
            dismiss();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

并监听目标片段中的消息:

private final BroadcastReceiver localReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Do whatever you need to do here
    }
};

@Override
protected void onStart() {
    super.onStart();

    final IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(MyDialogFragment.MY_ACTION);
    LocalBroadcastManager.getInstance(getContext())
        .registerReceiver(localReceiver, intentFilter);
}

@Override
protected void onStop() {
    super.onStop();
    LocalBroadcastManager.getInstance(this)
        .unregisterReceiver(localReceiver);
}
Run Code Online (Sandbox Code Playgroud)