Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

DialogFragment как анонимный внутренний класс

#android #android_studio #android_sdk


В книге Android для разработчиков 3е издание, авторы Пол Дейтел, Харви Дейтел, Александер
Уолд, есть пример, в котором DialogFragment, является анонимным внутренним классом.
Android Studio выводит сообщение "Fragments should be static such that they can be
re-instantiated by the system, and anonymous classes are not static".
Возник вопрос - в API андроида, произошли какие-то изменения, и больше невозможно
использовать фрагменты как анонимные классы? Или в книге были допущены ошибки? В книге
рассматривается API23, в AS API27

    private OnClickListener guessButtonListener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        Button guessButton = ((Button) v);
        String guess = guessButton.getText().toString();
        String answer = getCountryName(correctAnswer);
        ++totalGuesses; // Увеличение количества попыток пользователя

        if (guess.equals(answer)) { // Если ответ правилен
            ++correctAnswers; // Увеличить количество правильных ответов

            // Правильный ответ выводится зеленым цветом
            answerTextView.setText(answer + "!");
            answerTextView.setTextColor(
                getResources().getColor(R.color.correct_answer,
                    getContext().getTheme()));

            disableButtons(); // Блокировка всех кнопок ответов

            // Если пользователь правильно угадал FLAGS_IN_QUIZ флагов
            if (correctAnswers == FLAGS_IN_QUIZ) {
                // DialogFragment для вывода статистики и перезапуска
                DialogFragment quizResults =
                    new DialogFragment() {
                        // Создание окна AlertDialog    
                        @Override
                        public Dialog onCreateDialog(Bundle bundle) {
                            AlertDialog.Builder builder =
                                new AlertDialog.Builder(getActivity());
                            builder.setMessage(
                                getString(R.string.results,
                                    totalGuesses,
                                    (1000 / (double) totalGuesses)));

                            // Кнопка сброса "Reset Quiz"
                            builder.setPositiveButton(R.string.reset_quiz,
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog,
                                        int id) {
                                        resetQuiz();
                                    }
                                }
                            );

                            return builder.create(); // Вернуть AlertDialog
                        }
                    };

                // Использование FragmentManager для вывода DialogFragment
                quizResults.setCancelable(false);
                quizResults.show(getFragmentManager(), "quiz results");
            } else { // Ответ правильный, но викторина не закончена
                // Загрузка следующего флага после двухсекундной задержки
                handler.postDelayed(
                    new Runnable() {
                        @Override
                        public void run() {
                            animate(true); // Анимация исчезновения флага
                        }
                    }, 2000); // 2000 миллисекунд для двухсекундной задержки
            }
        } else { // Неправильный ответ
            flagImageView.startAnimation(shakeAnimation); // Встряхивание

            // Сообщение "Incorrect!" выводится красным шрифтом
            answerTextView.setText(R.string.incorrect_answer);
            answerTextView.setTextColor(getResources().getColor(
                R.color.incorrect_answer, getContext().getTheme()));
            guessButton.setEnabled(false); // Блокировка неправильного ответа
        }
    }
};

    


Ответы

Ответ 1



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

Ответ 2



Fragment не может быть анонимным классом. При восстановлении активити FragmentManager может попытаться создать фрагмент заново через рефлексию. Вы получите ошибку android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.squareup.MyActivity$1: make sure class name exists, is public, and has an empty constructor that is public

Ответ 3



С помощью этой ссылки удалось исправить ошибку: https://habr.com/ru/post/259805/ Необходимо создать класс, расширяющий DialogFragment. Он будет выводить наш диалог, а обрабатывать нажатие кнопки ОК будем в вызывающем фрагменте MainActivityFragment в методе onActivityResult, который получает код нажатой кнопки из вызываемого фрагмента AlertDialogFragment: import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; public class AlertDialogFragment extends DialogFragment { public static int totalGuesses; @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { totalGuesses = getTargetRequestCode(); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(getString(R.string.results, totalGuesses, (1000 / (double) totalGuesses))); builder.setPositiveButton(R.string.reset_quiz, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { getTargetFragment().onActivityResult(totalGuesses, Activity.RESULT_OK, null); } }); return builder.create(); } } В вызывающем фрагменте MainActivityFragment создадим метод showDialog, показывающий диалог, и обрабатываем нажатие кнопки ОК в методе onActivityResult: //show dialog at the end of the game public void showDialog() { DialogFragment fragment = new AlertDialogFragment(); fragment.setTargetFragment(this, totalGuesses); fragment.setCancelable(false); fragment.show(getFragmentManager(), "quiz results"); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) resetQuiz(); } Вместо кода с ошибкой пишем такой код: if (correctAnswers == FLAG_IN_QUIZ) { showDialog(); }

Комментариев нет:

Отправить комментарий