получить onActivityResult для фрагмента из действия, которое вызывается внутри RecyclerView.Adapter

хорошо, вот моя проблема

  1. У меня есть фрагмент, содержащий RecyclerView, и, конечно же, адаптер (называемый ApprovalCutiCardAdapter), содержащий содержимое.
  2. Внутри этого ApprovalCutiCardAdapter я устанавливаю OnClickListener на карту, когда нажимается карта, она запускает действие под названием DetailApprovalCuti. Вот мой код для запуска активности

    ((Activity) MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);
    
  3. В DetailApprovalCuti я выполняю finishActivity(1), чтобы получить событие onActivityResult. Но это событие не вызывается везде (в действии, в котором размещен фрагмент, и во фрагменте)

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.e("result", "ApprovalIzinCutiFragment");
        super.onActivityResult(requestCode, resultCode, data);
    }
    
  4. Вот мой код для запуска Acvitity

    @Override
    public void onBindViewHolder(final CutiViewHolder holder, final int position) {
    ....
    holder.cv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent detailApprovalCutiIntent = new Intent(MyApplication.getmContext(), DetailApprovalCuti.class);
            Bundle b = new Bundle();
            b.putParcelable("cuti", ApprovalCutiCardAdapter.allCuti.get(position));
            b.putParcelable("process_cuti", ApprovalCutiCardAdapter.allCuti.get(position).getProcessCuti());
            detailApprovalCutiIntent.putExtras(b);
            ((Activity)MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent,1);
        }
    });
    
    ....
    }
    
  5. Вот мой код для завершения действия

    btnReject.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new AlertDialog.Builder(DetailApprovalCuti.this)
                    .setTitle("Peringatan")
                    .setMessage("Apakah anda yakin?")
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            setResult(1);
                            finish();
                        }
                    }).setNegativeButton(android.R.string.no, null).show();
        }
    });
    

person Lyan Dwi Pangestu    schedule 31.07.2016    source источник
comment
Ваш А то, что событие не везде называется не понятно, что именно вы имеете в виду? В чем проблема и каково желаемое поведение?   -  person ddb    schedule 31.07.2016
comment
Я хочу прослушать событие, которое вызывается после закрытия DetailApprovalCuti, а это значит, что оно вернется к фрагменту, но onActivityResult на фрагменте не работает   -  person Lyan Dwi Pangestu    schedule 31.07.2016
comment
Вы получаете ошибку? Или вы хотели бы перенаправить ActivityOnResult на действие, в котором размещены фрагменты?   -  person ddb    schedule 31.07.2016
comment
Я не вижу никакой ошибки, Log внутри onActivityResult не работает, я хочу отправить данные из активности, которая закрыта, во фрагмент, содержащий RecyclerView   -  person Lyan Dwi Pangestu    schedule 31.07.2016
comment
Вы определили onActivityResult во фрагменте?   -  person ddb    schedule 31.07.2016
comment
да, я пробовал это на Фрагменте и на Активности, которые содержат Фрагмент, но ни один из них не работает   -  person Lyan Dwi Pangestu    schedule 31.07.2016
comment
Активность должна запускаться для результата фрагментом напрямую, поэтому, когда новая активность закрывается для результата, ваш код должен работать   -  person ddb    schedule 31.07.2016
comment
@ddb, но я должен запустить действие из RecyclerView.Adapter   -  person Lyan Dwi Pangestu    schedule 31.07.2016
comment
Проверьте этот вопрос stackoverflow.com/questions/17085729/   -  person ddb    schedule 31.07.2016
comment
Я думаю, что проблема заключается здесь ((Activity)MyApplication.getmContext()).startActivityForResult. Вы уверены, что этот контекст является именно тем экземпляром действия, результаты которого вы хотите прослушивать? Вы пробовали использовать fragment.getActivity().startActivityForResult ()? (учитывая, что адаптер находится внутри Фрагмента)   -  person Sufian    schedule 01.08.2016
comment
@Sufian Я решил эту проблему, мне просто нужно извлечь слушателя в Fragment, чтобы я мог вызывать startActivityForResult напрямую, не получая контекст, спасибо, чувак   -  person Lyan Dwi Pangestu    schedule 01.08.2016


Ответы (3)


Проблема в том, что в следующей строке вы вызываете startActivityForResult() из действия, которое может быть не тем, которое вы ожидаете.

((Activity)MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);

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

fragment.getActivity().startActivityForResult(detailApprovalCutiIntent, 1);

Урок выучен

Никогда не используйте одиночки, поскольку одиночки — патологические лжецы.

PS: одиночные экземпляры — это хорошо, но одиночные экземпляры (например, глобальные переменные) — это плохой дизайн, и их следует избегать.

person Sufian    schedule 01.08.2016

Ваш Activity должен быть запущен "для результатов" фрагментом, например: startActivityForResult(detailApprovalCutiIntent, 1); вместо ((Activity) MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);-, а затем в Activity, на котором размещен фрагмент, вы можете обработать onActivityResult - но тогда вы хотите распространить это событие к Fragment. Итак, вы вызываете super.onActivityResult(requestCode, resultCode, data); - у вас будет что-то вроде:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);   
}

Затем во фрагменте вы можете обработать обратный вызов onActivityResult.

Пожалуйста, взгляните на эти тесно связанные вопросы и попробуйте выбранные ответы:

Надеюсь, это прольет свет.

person ishmaelMakitla    schedule 31.07.2016
comment
Я не могу выполнить startActivityForResult(detailApprovalCutiIntent, 1);, потому что он вызывается внутри адаптера. startActivityForResult нельзя вызвать из адаптера - person Lyan Dwi Pangestu; 31.07.2016
comment
@LyanDwiPangestu вы можете сохранить WeakReference в Activity в поле внутри вашего адаптера. Хотя я чувствую, что есть проблема в том, как ты заканчиваешь следующий Activity. Вы должны вызвать setResult(), а затем finish(), чтобы активность вашего адаптера была вызвана onActivityResult(). - person Sufian; 31.07.2016
comment
@Sufian, не могли бы вы привести пример того, что такое WeakReference? - person Lyan Dwi Pangestu; 31.07.2016
comment
@LyanDwiPangestu См. это. Просто сохраните ссылку на Activity в своем адаптере, и это не должно быть проблемой. Как я уже говорил, проблема в том, как вы закончите следующую деятельность. - person Sufian; 31.07.2016
comment
@LyanDwiPangestu также см. это для WeakReference - stackoverflow.com/questions/299659/ - person Sufian; 31.07.2016
comment
@Sufian Я изменил способ завершения действия, но он все еще не работает, не пробовал с WeakReference - person Lyan Dwi Pangestu; 31.07.2016
comment
@LyanDwiPangestu, пожалуйста, обновите свой вопрос, указав последний код. Покажите фрагменты, где вы делаете startActivityForResult(), setResult() и finish(). - person Sufian; 31.07.2016

Я думаю, что ваш дизайн излишне сложен и слишком тесно связывает Activity, Fragment и адаптер RecyclerView.

Попробуйте это вместо этого:

  • когда адаптер обнаруживает щелчок по карте, он сообщает об этом своему родителю (в данном случае — фрагменту).
  • когда Фрагмент уведомляется о щелчке, он уведомляет своего родителя (Действие)
  • когда действие уведомляется фрагментом, пусть оно (действие) запускает новое действие с помощью startActivityForResult
  • когда действие получает результат в onActivityResult, пусть оно делает все, что ему нужно, с результатом. Если этот результат необходим во Фрагменте, пусть он передаст результат Фрагменту.

Следующий вопрос заключается в том, как общаться между Фрагментом и Активностью. «Стандартный» ответ состоит в том, чтобы создать пару интерфейсов и реализовать один из них в Activity, а другой — в Fragment, а затем использовать методы интерфейса для обратного и обратного вызова.

Это может быть сложно сделать правильно, потому что Activity и Fragment должны тщательно отслеживать жизненные циклы друг друга, чтобы избежать сбоя.

Я считаю, что лучшим и более простым решением является использование шины сообщений (например, Otto) для обмена сообщениями между ними. Таким образом, Activity и Fragment должны регистрироваться и отменять регистрацию на шине только тогда, когда они готовы, и вы полностью обходите проблемы жизненного цикла.

person GreyBeardedGeek    schedule 31.07.2016