Могу ли я передать интерфейс для связки фрагмента? - PullRequest
0 голосов
/ 09 мая 2018

Поскольку фрагменты должны выдерживать изменение конфигурации, Android настоятельно рекомендует при создании фрагмента реализовать собственный метод newInstance(), передавая необходимые данные в Bundle вместо использования new MyFragment().

.

Теперь проблема в том, Я хочу передать обратный вызов (интерфейс) этому фрагменту .

Сначала я попытался сделать свой интерфейс extends Serializable, и просто использовал args.putSerializable("myInterface", myInterface).
Но когда Android пытается сохранить свое состояние (посылать его), создается исключение (Parcelable обнаружил IOException, записывая сериализуемый объект).

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

Итак, есть ли способ, с помощью которого я могу позволить пользователю передать обратный вызов фрагменту и иметь возможность пережить изменение конфигурации (например, ротацию устройства)?

UPDATE

По запросу, вот интерфейс, который я хочу передать:

public interface OnImageSelectedListener extends Serializable {
    void onImageSelected (String uri);
}

И как я строю этот интерфейс:

new OnImageSelectedListener() {
        @Override
        public void onSingleImageSelected(String uri) {
            Glide.with(MainActivity.this).load(uri).into(ivImage);
        }
}

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Наконец, я прихожу к выводу:

Мы не должны сохранять обратный вызов.

Представьте, что обратный вызов выполняет следующий код:
Glide.with(context).load(image).into(imageView);

Когда устройство вращается, вышеприведенный imageView, который принадлежит деятельности или другому фрагменту, также уничтожается и воссоздается. Старый ImageView, на который есть ссылка в сохраненном обратном вызове, больше не существует.

Это либо заставит Glide бросить исключение; или утечка старого ImageView и, таким образом, всего Activity.

Вот почему мы всегда должны ссылаться на обратный вызов для присоединения Activity.
И если вызывающий является Fragment, вместо ссылки на обратный вызов в onAttach(), просто ссылайтесь на родительский фрагмент в onCreateView():

if (getParentFragment() != null && getParentFragment() instanceof YourInterface) {
    yourCallback = (YourInterface) getParentFragment();
}

Так что, если ответить на оригинальный вопрос,

Можно ли передать интерфейс в связку фрагмента?

Ответ, вероятно, нет, но вы просто не должны.

0 голосов
/ 09 мая 2018

Причина, по которой вы сталкиваетесь с этой проблемой, заключается в том, что Glide не является сериализуемыми данными, и вы не можете сериализовать их. Поскольку сериализация - это процесс, определенный в Java и выполняемый в JVM, он не понимает Parcelable, поэтому завершается с ошибкой. Это также применимо, даже если вы просто используете их в методе обратного вызова.

Но поскольку вы разрабатываете библиотеку, вы не сможете контролировать использование вашего интерфейса обратного вызова. Таким образом, решением было бы избежать отправки этого объекта путем его сериализации.

Вместо этого, когда запускается сценарий использования вашей библиотеки (должна быть какая-то точка входа для изменения варианта использования), вам нужно запросить передачу прямой ссылки на ваш метод. Затем вы можете сохранить ссылку и выполнить обратный вызов при необходимости. Вам нужно реализовать некоторые обертки для достижения этого. И общаться внутри страны через LocalBroadcastReceiver

Если описанный выше подход невозможен, то единственным решением будет попросить пользователя вашей библиотеки зарегистрироваться для LocalBroadcastReceive и доставить результат через Broadcast.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...