如何设计可重用的DialogFragment

时间:2013-06-26 10:59:02

标签: android android-dialogfragment

这个问题已经存在一些问题,但对我来说并不是很有帮助。所以这里有一个新的。

我有一个有两个标签的Activity。每个选项卡都包含一个ListFragment(确切地说就是SherlockListFragment)。一个选项卡显示购物清单对象列表,另一个选项卡显示配方对象列表。现在我想创建一个DialogFragment来重命名列表或配方或我以后可能添加到应用程序中的任何其他对象。

这里提供的解决方案听起来很有希望,但是因为ListFragment无法注册来监听对话框中的点击,我应该让我的Activity听它们不理想因为那时我的片段不会是独立的。 How to get data out of a general-purpose dialog class

理想情况下,我希望我的重命名对话框尽可能独立且可重复使用。到目前为止,我发明了一种方法来做到这一点。将对象className和id发送到对话框,然后使用switch case从数据库中获取正确的对象。这样,对话框就能够自己更新对象名称(如果对象具有重命名方法)。但是对数据库的重新查询听起来只是转储,因为ListFragment已经有了对象。然后对话框需要在交换机中为每种新对象提供一个新案例。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我实际上只是根据您的要求创建了一个类似的对话框片段。我是一个相当大的应用程序,我们的主要活动只是为了听取单个对话框的结果而扩展的对话监听器的数量变得有点荒谬。

为了使某些内容更灵活,我转而使用Google的Guava并发库中的ListenableFuture。

我创建了以下要使用的抽象类:

public abstract class ListenableDialogFragment<T> extends DialogFragment implements ListenableFuture<T> {

private SettableFuture<T> _settableFuture;

public ListenableDialogFragment() {
    _settableFuture = SettableFuture.create();
}

@Override
public void addListener(Runnable runnable, Executor executor) {
    _settableFuture.addListener(runnable, executor);
}

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
    return _settableFuture.cancel(mayInterruptIfRunning);
}

@Override
public boolean isCancelled() {
    return _settableFuture.isCancelled();
}

@Override
public boolean isDone() {
    return _settableFuture.isDone();
}

@Override
public T get() throws InterruptedException, ExecutionException {
    return _settableFuture.get();
}

@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    return _settableFuture.get(timeout, unit);
}

public void set(T value) {
    _settableFuture.set(value);
}

public void setException(Throwable throwable) {
    _settableFuture.setException(throwable);
}

// Resets the Future so that it can be provided to another call back
public void reset() {
    _settableFuture = SettableFuture.create();
}

@Override
public void onDismiss(DialogInterface dialog) {
    // Cancel the future here in case the user cancels our of the dialog
    cancel(true);
    super.onDismiss(dialog);
}

使用这个类,我可以创建自己的自定义对话框片段并像这样使用它们:

            ListenableDialogFragment<int> dialog = GetIdDialog.newInstance(provider.getIds());

    Futures.addCallback(dialog, new FutureCallback<int>() {
        @Override
        public void onSuccess(int id) {
            processId(id);
        }

        @Override
        public void onFailure(Throwable throwable) {
            if (throwable instanceof CancellationException) {
                // Task was cancelled
            }

            processException(throwable);
        }
    });

这是GetIdDialog是ListenableDialogFragment的自定义实例的地方。如果需要,我可以通过简单地在onSuccess和onFailure方法中调用dialog.reset来重用这个相同的对话框实例,以确保重新加载内部Future以添加回回调。

我希望这可以帮助你。

编辑:抱歉忘了添加,在你的对话框中你可以实现一个点击监听器来做这样的事情来触发未来:

private class SingleChoiceListener implements DialogInterface.OnClickListener {
    @Override
    public void onClick(DialogInterface dialog, int item) {
        int id = _ids[item];

        // This call will trigger the future to fire
        set(id);
        dismiss();
    }
}

答案 1 :(得分:1)

我可能只是使用一些变体的静态工厂模式来允许动态初始化DialogFragment。

private enum Operation {ADD, EDIT, DELETE}

private String title;
private Operation operation;

public static MyDialogFragment newInstance(String title, Operation operation)
{
    MyDialogFragment dialogFragment = new DialogFragment();
    dialogFragment.title = title;   // Dynamic title
    dialogFragment.operation = operation;

    return dialogFragment;
}

或..我会更推荐这个,为你将使用它的每种操作都有一个静态工厂方法。这允许不同的动态变化更具体,并确保一切都在一起工作。这也允许信息丰富的构造函数。

例如

public static MyDialogFragment newAddItemInstance(String title)
{
    MyDialogFragment dialogFragment = new DialogFragment();
    dialogFragment.title = title;   // Dynamic title

    return dialogFragment;
}

public static MyDialogFragment newEditItemInstance(String title)
{
    MyDialogFragment dialogFragment = new DialogFragment();
    dialogFragment.title = title;   // Dynamic title

    return dialogFragment;
}

然后当然创建一个接口,每个调用Activity / Fragment(在这种情况下,您需要将此Fragment设置为targetFragment并在DialogFragment中获取对该目标Fragment的引用),以便在target Fragment与DialogFragment无关。

摘要:有很多方法可以实现这一点,为简单起见,我会坚持使用某种形式的静态工厂模式,并巧妙地使用接口将任何逻辑与DialogFragment分开,从而使它更可重复使用

编辑:根据您的评论,我建议您查看两件事:

  • 目标碎片(请参阅我在您的问题上所做的评论)。您可以从DialogFragment调用ListFragment中的方法。

  • 战略模式。 How does the Strategy Pattern work?。这允许您在不同对象上执行相同的操作(针对每种类型的各种定制实现)。非常有用的模式。