Android "Лучшая практика" возвращает значения из диалогового окна



каков " правильный "способ возврата значений к вызывающей активности из сложного пользовательского диалога - скажем, текстовые поля, выбор даты или времени, куча переключателей и т. д., а также кнопка" Сохранить "и" отменить"?



некоторые из методов, которые я видел в интернете, включают:




  • открытые члены данных в диалоговом производном классе, которые могут быть прочитаны Activity


  • общедоступные методы доступа "get". . . ". . ". . "


  • запуск диалога с намерением (в отличие от показать() ) плюс обработчики в классе Dialog, которые принимают входные данные от различных элементов управления и связывают их для передачи обратно в действие, поэтому, когда слушатель нажимает "сохранить", пакет передается обратно с помощью ReturnIntent ()


  • слушатели в действии, которые обрабатывают ввод от элементов управления, которые находятся в диалоговом окне, например, так что TimePicker или DatePicker слушатели действительно находятся в деятельности. В этой схеме практически вся работа выполняется в деятельности


  • один слушатель в действии для кнопки "Сохранить", а затем действие непосредственно опрашивает элементы управления в диалоговом окне; действие отклоняет диалоговое окно.



...плюс еще кое-что, что я уже забыл.



есть ли определенная техника, которая считается канонически правильной или " лучшей практикой" метод?

556   6  

6 ответов:

Я использую следующий способ:

  1. все мои действия имеют одну и ту же родительскую активность (скажем, ControlActivity). ControlActivity имеет private volatile Bundle controlBundle; С соответствующим геттером / сеттером
  2. когда я начинаю диалог, я использовал, чтобы вызвать диалог через мой собственный метод:

    public void showMyDialog(int id, Bundle bundle)
    {
        this.controlBundle=bundle;
        this.showDialog(id, bundle);
    }
    

поэтому каждый раз, когда я знаю параметры, отправленные в dialog

  1. когда диалог собирается завершить, я формирую в диалоге другой Bundle С необходимые значения, а затем положить их через мой Activity пакета сеттер:

((ControlActivity )this.getOwnerActivity).setControlBundle(bundle);

так что в конце концов, когда диалог заканчивается, я знаю значение "возвращено" из диалога. Я знаю, что это не так int retCode=this.showMyDialog(); это немного сложнее, но это выполнимо.

возможно, я неправильно понимаю ваш вопрос, но почему бы просто не использовать встроенную систему прослушивания:

builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        // run whatever code you want to run here
        // if you need to pass data back, just call a function in your
        // activity and pass it some parameters
    }
})

вот как я всегда обрабатывал данные из диалоговых окон.

EDIT: позвольте мне дать вам более конкретный пример, который лучше ответит на ваш вопрос. Я собираюсь украсть некоторые примеры кода с этой страницы, которые вы должны читайте:

http://developer.android.com/guide/topics/ui/dialogs.html

// Alert Dialog code (mostly copied from the Android docs
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pick a color");
builder.setItems(items, new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int item) {
        myFunction(item);
    }
});
AlertDialog alert = builder.create();

...

// Now elsewhere in your Activity class, you would have this function
private void myFunction(int result){
    // Now the data has been "returned" (as pointed out, that's not
    // the right terminology)
}

для моего MIDI-приложения мне нужны были диалоги подтверждения да / нет / отмена, поэтому я сначала сделал общий класс StandardDialog:

public class StandardDialog {

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.os.Handler;

    public class StandardDialog {
    public static final int dlgResultOk         = 0;
    public static final int dlgResultYes        = 1;
    public static final int dlgResultNo         = 2;
    public static final int dlgResultCancel     = 3;

    public static final int dlgTypeOk           = 10;
    public static final int dlgTypeYesNo        = 11;
    public static final int dlgTypeYesNoCancel  = 12;

    private Handler mResponseHandler;
    private AlertDialog.Builder mDialogBuilder;
    private int mDialogId;

    public StandardDialog(Activity parent, 
                          Handler reponseHandler, 
                          String title, 
                          String message, 
                          int dialogType, 
                          int dialogId) {

        mResponseHandler = reponseHandler;
        mDialogId = dialogId;
        mDialogBuilder = new AlertDialog.Builder(parent);
        mDialogBuilder.setCancelable(false);
        mDialogBuilder.setTitle(title);
        mDialogBuilder.setIcon(android.R.drawable.ic_dialog_alert);
        mDialogBuilder.setMessage(message);
        switch (dialogType) {
        case dlgTypeOk:
            mDialogBuilder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mResponseHandler.sendEmptyMessage(mDialogId + dlgResultOk);
                }
            });         
            break;

        case dlgTypeYesNo:
        case dlgTypeYesNoCancel:
            mDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mResponseHandler.sendEmptyMessage(mDialogId + dlgResultYes);
                }
            });         
            mDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mResponseHandler.sendEmptyMessage(mDialogId + dlgResultNo);
                }
            });         
            if (dialogType == dlgTypeYesNoCancel) {
                mDialogBuilder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        mResponseHandler.sendEmptyMessage(mDialogId + dlgResultCancel);
                    }
                });         
            }
            break;
        }
        mDialogBuilder.show();
    }
}

далее в моей основной деятельности у меня уже был обработчик сообщений для обновления UI из других потоков, так что я просто добавил код для обработки сообщений от окна. Используя другой параметр dialogId при создании экземпляра StandardDialog для различных функций программы, я могу выполнить правильный код для обработки ответов yes / no / cancel для разных функций вопросы. Эта идея может быть расширена для сложных пользовательских диалогов, отправив пакет данных, хотя это намного медленнее, чем простое целочисленное сообщение.

private Handler uiMsgHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
        if (msg != null) {

            // {Code to check for other UI messages here}

            // Check for dialog box responses
            if (msg.what == (clearDlgId + StandardDialog.dlgResultYes)) {
                doClearDlgYesClicked();
            }
            else if (msg.what == (recordDlgId + StandardDialog.dlgResultYes)) {
                doRecordDlgYesClicked();
            }
            else if (msg.what == (recordDlgId + StandardDialog.dlgResultNo)) {
                doRecordDlgNoClicked();
            }
        }
    }
};

тогда все, что мне нужно сделать, это определить методы do{Whatever}() в действии. Чтобы вызвать диалог, в качестве примера у меня есть метод, отвечающий на кнопку" Очистить записанные MIDI-события " и подтвердите его следующим образом:

public void onClearBtnClicked(View view) {
    new StandardDialog(this, uiMsgHandler, 
        getResources().getString(R.string.dlgTitleClear),
        getResources().getString(R.string.dlgMsgClear), 
        StandardDialog.dlgTypeYesNo, clearDlgId);
}

clearDlgId определяется как уникальное целое число в другом месте. Этот метод создает диалоговое окно да / нет всплывает перед действием, которое теряет фокус, пока диалоговое окно не закроется, и в это время действие получает сообщение с результатом диалога. Затем обработчик сообщений вызывает doClearDlgYesClicked() метод, если была нажата кнопка" да". (Мне не нужно было сообщение для кнопки "нет", так как в этом случае никаких действий не требовалось).

в любом случае, этот метод работает для меня, и позволяет легко передавать результаты обратно из диалога.

я размышлял над этим сам некоторое время, и в конечном итоге самый удобный способ, который я нашел для этого, - это разбить мою деятельность на различные методы, которые представляют каждую единицу потока управления. Например, если действия в моей деятельности говорят : загрузите переменные из intent, проверьте некоторые данные, обработайте и продолжите, если доступно, если нет фонового вызова, дождитесь взаимодействия с пользователем, начните другое действие.

я вообще пикап части, которые являются общими, первые два и последний в данном случае. Я заверну первые в onCreate() и сделать отдельный для последнего... скажи startAnotherActivity(Data). Вы можете расположить средние части так, чтобы они состояли из checkData(Data) (возможно, слилась в onCreate()), которая вызывает либо processAvailableData(Data) или performBackgroundTask(Data). Фоновая задача выполнит операцию в фоновом режиме и вернет управление в onBackgroundTaskCompleted(OtherData).

теперь processAvailableData(Data) и onBackgroundTaskCompleted(OtherData) вызов getUserResponse() метод, который, в свою очередь, может либо вызов startAnotherActivity(Data) или слить его функционирует сам с собой.

я чувствую, что этот подход дает ряд преимуществ.

  1. это помогает с вопросом возврата данных, на который указывает ваш вопрос, "двигаясь вперед" вместо возврата данных.
  2. это позволяет легче добавлять новые функции. Например, если бы мы хотели дать пользователю больше возможностей, мы могли бы просто вызвать соответствующий метод из getUserResponse() что может повлиять на данные, которые в конечном итоге передаются следующему деятельность.
  3. это помогает избежать ненужных проблем потока (проверьте вопросы, связанные с finish() и return on SO), когда наше интуитивное предположение-это определенный поток, а он оказывается другим.
  4. помогает лучше управлять переменными, поэтому у вас не будет много полей уровня класса, чтобы избежать проблем с доступом к переменным в анонимных внутренних классах (onClick (), doInBackground () и т. д.).

я уверен, что больше методов добавляет некоторые накладные расходы, но его, вероятно, компенсируются преимуществами потока, повторного использования и простоты, которые вы получаете (хотелось бы услышать мнение эксперта по компиляции об этом).

я объясню одно решение на примере двух фрагментов. Представьте, что есть SimpleFragment, который имеет только одно текстовое поле для отображения даты. То есть DatePickerFragment что позволяет выбрать конкретную дату. То, что я хочу, это то, что DatePickerFragment передает значение даты обратно в вызов SimpleFragment всякий раз, когда пользователь подтверждает ее выбор.

SimpleFragment

Итак, прежде всего мы начинаем DatePickerFragment внутри SimpleFragment:

private DateTime mFavoriteDate; // Joda-Time date

private void launchDatePicker() {
    DatePickerFragment datePickerFragment = new DatePickerFragment();
    Bundle extras = new Bundle();
    // Pass an initial or the last value for the date picker
    long dateInMilliSeconds = mFavoriteDate.getMillis();
    extras.putLong(BundleKeys.LAST_KNOWN_DATE, dateInMilliSeconds);
    datePickerFragment.setArguments(extras);
    datePickerFragment.setTargetFragment(this, SIMPLE_FRAGMENT_REQUEST_CODE);
    datePickerFragment.show(getActivity().getSupportFragmentManager(),
            DatePickerFragment.FRAGMENT_TAG);
}

DatePickerFragment

во фрагменте диалогового окна мы готовимся передать назад выбранную дату, когда пользователь нажимает положительную кнопку:

public static final String DATE_PICKED_INTENT_KEY = "DATE_PICKED_INTENT_KEY";
public static final int DATE_PICKED_RESULT_CODE = 123;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // ...
    Long dateInMilliSeconds = getArguments().getLong(BundleKeys.LAST_KNOWN_DATE);
    DateTime date = new DateTime(dateInMilliSeconds);
    initializePickerUiControl(date);

    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity);
    dialogBuilder
        .setPositiveButton(R.string.date_picker_positive, (dialog, which) -> {
            // Pass date to caller
            passBackDate();
        })
        .setNegativeButton(R.string.date_picker_negative, (dialog, which) -> {
            // Nothing to do here
        });
    return dialogBuilder.create();
}

private void passBackDate() {
    DateTime dateTime = getDateTimeFromPickerControl();
    Intent intent = new Intent();
    intent.putExtra(DATE_PICKED_INTENT_KEY, dateTime.getMillis());
    getTargetFragment().onActivityResult(
            getTargetRequestCode(), DATE_PICKED_RESULT_CODE, intent);
}

SimpleFragment

назад в запрашивающем фрагменте мы потребляем то, что было передано обратно диалогом:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == SIMPLE_FRAGMENT_REQUEST_CODE &&
            resultCode == DatePickerFragment.DATE_PICKED_RESULT_CODE) {
        long datePickedInMilliseconds = data.getLongExtra(
                DatePickerFragment.DATE_PICKED_INTENT_KEY, 0);
        mFavoriteDate = new DateTime(datePickedInMilliseconds);
        updateFavoriteDateTextView();
    }
    else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

ссылки mattpic кто дал отличный ответ!--25--> раньше.

после совсем немного исследований я остановился на интерфейсе обратного вызова. Мой код выглядит следующим образом:

MyFragment.java

public class MyFragment extends Fragment {

...

private void displayFilter() {

    FragmentManager fragmentManager = getFragmentManager();

    FilterDialogFragment filterDialogFragment = new FilterDialogFragment();
    Bundle bundle = new Bundle();
    bundle.putSerializable("listener", new FilterDialogFragment.OnFilterClickListener() {
        @Override
        public void onFilterClickListener() {
            System.out.println("LISTENER CLICKED");

        }
    });
    filterDialogFragment.setArguments(bundle);
    filterDialogFragment.show(fragmentManager, DIALOG_FILTER);

}

MyDialog.java

public class MyDialog extends DialogFragment {

private ImageButton mBtnTest;
private OnFilterClickListener mOnFilterClickListener;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Get the layout inflater
    LayoutInflater inflater = getActivity().getLayoutInflater();
    View filterLayout = inflater.inflate(R.layout.filter_dialog, null);
    // Inflate and set the layout for the dialog
    // Pass null as the parent view because its going in the dialog layout
    builder.setView(filterLayout)
            .setTitle("Filter");

    Dialog dialog = builder.create();

    mOnFilterClickListener = (OnFilterClickListener) getArguments().getSerializable("listener");

    mBtnTest = (ImageButton)filterLayout.findViewById(R.id.fandb);
    mBtnTest.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            mOnFilterClickListener.onFilterClickListener();
            dismiss();
        }
    });

    return dialog;
}

public interface OnFilterClickListener extends Serializable {
    void onFilterClickListener();
}

}

Comments

    Ничего не найдено.