Получение результата из DialogFragment

Интерфейс, диалоги, темы, стили, меню
Ответить
slbel
Сообщения: 36
Зарегистрирован: 31 мар 2015, 13:25

Получение результата из DialogFragment

Сообщение slbel » 04 май 2015, 18:03

Доброго всем времени суток!

Как получить результат из DialogFragment без упоминания имени класса активити вызвавшего данный диалог внутри реализации DialogFragment? Хотел бы реализовать некий универсальный класс диалога, который бы не зависел от вызвавшего его Activity. Пока не могу собрать (изобрести) велосипед на основе имеющихся у меня сведений. Получается, что для каждого активити приложения, которому требуется некий диалог нужно вводить отдельный класс DialogFragment, чтобы спросить пользователя о чем-нибудь?!

Все классические примеры которые я нашел в инете всегда упоминают имя класса вызвавшей DialogFragment активити.

Чтобы не затруднять форумчан лазанием по всяким докам, приведу классический пример для AlertDialog.

Код: Выделить всё

public static class MyAlertDialogFragment extends DialogFragment {

    public static MyAlertDialogFragment newInstance(int title) {
        MyAlertDialogFragment frag = new MyAlertDialogFragment();
        Bundle args = new Bundle();
        args.putInt("title", title);
        frag.setArguments(args);
        return frag;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        int title = getArguments().getInt("title");

        return new AlertDialog.Builder(getActivity())
                .setIcon(R.drawable.alert_dialog_icon)
                .setTitle(title)
                .setPositiveButton(R.string.alert_dialog_ok,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((FragmentAlertDialog)getActivity()).doPositiveClick();
                        }
                    }
                )
                .setNegativeButton(R.string.alert_dialog_cancel,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((FragmentAlertDialog)getActivity()).doNegativeClick();
                        }
                    }
                )
                .create();
    }
}
Как выглядит обработка результата в основном активити, вызывающем MyAlertDialogFragment.

Код: Выделить всё

void showDialog() {
    DialogFragment newFragment = MyAlertDialogFragment.newInstance(
            R.string.alert_dialog_two_buttons_title);
    newFragment.show(getFragmentManager(), "dialog");
}

public void doPositiveClick() {
    // Do stuff here.
    Log.i("FragmentAlertDialog", "Positive click!");
}

public void doNegativeClick() {
    // Do stuff here.
    Log.i("FragmentAlertDialog", "Negative click!");
}
Не понимаю, как избавиться от упоминания FragmentAlertDialog?

Код: Выделить всё

public void onClick(DialogInterface dialog, int whichButton) {
                            ((FragmentAlertDialog)getActivity()).doNegativeClick();
}

Нежели для возврата результата, нужно знать, имя вызвавшей его Активити?! Мутно как-то.

И так во всех сниппетах, которые мне удалось найти.

PS: Кстати автор блога в уроке 110 http://startandroid.ru/ru/uroki/vse-uro ... ialog.html

поступил довольно хитро (мудро) выдав результат в этом же диалоге! А как передать результат диалога в вызвавшую его активити скромно умолчал :) Ведь диалоги в основном для того и служат, чтобы вернуть результат куда-то.

Аватара пользователя
doter.ua
Сообщения: 1106
Зарегистрирован: 23 ноя 2013, 16:08
Откуда: Ukraine

Re: Получение результата из DialogFragment

Сообщение doter.ua » 04 май 2015, 20:01

Положить в диалог: в конструкторе.
Вернуть из диалога: интерфейсом.

Код: Выделить всё

public abstract class MyDialog extends DialogFragment implements MyListener{

    //в момент закрытия:
    setResult( "bla bla" );
    dismiss(); // собсна само закрытие.

}
где implements MyListener -интерфейс, описывающий метод в который будет передавать результат:

Код: Выделить всё

public interface MyListener{
    void setResult( Strring result );
}
В самом диалоге нигде не описан этот метод, только его вызов setResult( "bla bla" );
Когда будешь создавать диалог MyDialog = new MyDialog (); он потребует определить этот метод (как при онКлик). В нем и пишется код, обрабатывающий результат.
Семь раз отмерь - поставь студию.
Эклипс не студия, ошибка вылетит - не исправишь.
Скажи мне кто твой друг, и оба поставили студию.
Студия - свет, а эклипс - тьма.

slbel
Сообщения: 36
Зарегистрирован: 31 мар 2015, 13:25

Re: Получение результата из DialogFragment

Сообщение slbel » 04 май 2015, 21:50

doter.ua писал(а):Положить в диалог: в конструкторе.
Вернуть из диалога: интерфейсом.

Код: Выделить всё

public abstract class MyDialog extends DialogFragment implements MyListener{
В самом диалоге нигде не описан этот метод, только его вызов setResult( "bla bla" );
Когда будешь создавать диалог MyDialog = new MyDialog (); он потребует определить этот метод (как при онКлик). В нем и пишется код, обрабатывающий результат.
Спасибо за идею. Более подробно написано в разделе Creating event callbacks to the activity http://developer.android.com/guide/comp ... ments.html. Единственная неточность в вашем примере:

Код: Выделить всё

public abstract class MyDialog extends DialogFragment implements MyListener{
класс диалога не должен реализовывать интерфейс, иначе непонятно как выполнить присвоение результата. Должно быть так:

Код: Выделить всё

public abstract class MyDialog extends DialogFragment{
Кстати, не понял зачем abstract?

Наткнулся на ещё одну реализацию возврата результата: http://stackoverflow.com/questions/1090 ... ogfragment
Но запнулся на строке: dialogFrag.setTargetFragment(this, 1);

Код: Выделить всё

DialogFragment dialogFrag = new MyDialogFragment();
// This is the requestCode that you are sending.
dialogFrag.setTargetFragment(this, 1);     
// This is the tag, "dialog" being sent.
dialogFrag.show(getFragmentManager(), "dialog");
Непонятно где взять фрагмент для активити в котором вообще их нет. Искусственно что ли создать?

Аватара пользователя
doter.ua
Сообщения: 1106
Зарегистрирован: 23 ноя 2013, 16:08
Откуда: Ukraine

Re: Получение результата из DialogFragment

Сообщение doter.ua » 04 май 2015, 23:02

slbel писал(а): Кстати, не понял зачем abstract?
когда имплементируешь интерфейс он требует чтобы ты добавил его методы, в нашем случае - setResult. Если ты не добавишь этот метод то весь класс (диалог) нужно объявить абстрактным. В следствии абстрактный диалог перекинет эту обязанность (добавление метода) на тот класс, в котором создаешь диалог(т.е. в активити). И тут история повторяется: либо добавляешь метод либо делаешь класс абстрактным. Логично, что в активити выберут "добавление метода"
Т.е. создаешь диалог:
MyDialog dlg = new MyDialog(... что-то передаешь); Андроид студия подчеркнет создание красным.
Ставим курсор в эту строчку и шаманим ( ALT + ENTER ) появится варианты решения проблемы, где выбираем implements methods.

Для примера можешь в активити написать такую штуку:
View.OnClickListener test= new View.OnClickListener();
Будет тот же эффект. (подчеркнет красным, типа используешь абстрактную штуку и не добавил ее методы )

З,Ы. еще можно вместо имплементации в диалоге добавить ему обьект (как переменную).
private MyListener listener;
и добавить геттер\сеттер
типа создал диалог и если захотел написал майДиалог.сетЛисенер( нью лисенер ... ). Своего рода необязательная фича.
Семь раз отмерь - поставь студию.
Эклипс не студия, ошибка вылетит - не исправишь.
Скажи мне кто твой друг, и оба поставили студию.
Студия - свет, а эклипс - тьма.

парень
Сообщения: 223
Зарегистрирован: 30 мар 2013, 22:52

Re: Получение результата из DialogFragment

Сообщение парень » 06 май 2015, 04:55

У меня так:

[syntax=java5]
public class dialog_budget extends DialogFragment implements OnClickListener {
Double mBudget;
View mDV;
onDialogBudgetListener dialogBudgetListener;

public interface onDialogBudgetListener {

public void eventBudget(Double mBudget);

}

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

getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
Bundle bun = this.getArguments();
mBudget=bun.getDouble("mBudget");

mDV = inflater.inflate(R.layout.dialog_subcat_new, null);

EditText ed = (EditText) mDV.findViewById(R.id.editSubCat);
ed.setText(""+mBudget);

mDV.findViewById(R.id.butCancel).setOnClickListener(this);
mDV.findViewById(R.id.butOk).setOnClickListener(this);

return mDV;
}

public void onAttach(Activity activity) {
super.onAttach(activity);
try {
dialogBudgetListener = (onDialogBudgetListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement onSomeEventListener");
}
}


public void onClick(View v) {
switch (v.getId()) {
case R.id.butOk:
mBudget= Double.valueOf(((EditText) mDV.findViewById(R.id.editSubCat)).getText().toString());
dialogBudgetListener.eventBudget(mBudget);
dismiss();
break;
case R.id.butCancel:
dismiss();
break;
}
}
}[/syntax]

А в активити вызывающим этот диалог (их несколько)

[syntax=java5]

public class LookRashod extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor>, dialog_budget.onDialogBudgetListener

... код

@Override
public void eventBudget(Double mBudget) {
((TextView)findViewById(R.id.tvBudgetTxt)).setText("" + mBudget);
... // далее изменение бд
}

... код

[/syntax]
Мой первенец: MyMoney. Менеджер расходов

Бьем рекорды русских топов :)

Могу ответить на любые вопросы по маркетингу и развитию.

Ответить