Сохранить/обновить данные EditText фрагмента в FragmentStatePagerAdapter

Введение

У меня есть действие с книгой, которая содержит список массивов типа «страница», и для обработки всех страниц я решил использовать FragmentStatePagerAdapter, в котором один из моих фрагментов содержит одну страницу.

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

У каждого фрагмента есть EditText, в котором пользователь может писать, и я установил addTextChangedListener, чтобы ловить момент, когда пользователь перестает писать. Когда пользователь перестает писать в EditText, в onTextChanged() я вызываю функцию, реализованную в отце активности.

Это мой код активности

public class BookEditorActivity implements BookEditorFragment.EditorFrToEditorActInterface {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.book_editor_activity);

        Bundle extras = getIntent().getExtras();
        b = (Book) extras.get("book");

        setBookViewPager(b);

    }

    private void setBookViewPager(Book b) {
        mBookViewPager = (ViewPager) findViewById(R.id.book_editor_pager);
        mBookViewPagerAdapter = new BookViewPagerAdapter(getSupportFragmentManager(), b);
        mBookViewPager.setAdapter(mBookViewPagerAdapter);
    }

    @Override
    public void saveBookPageTextContent(String textContent) {

        int current = mBookViewPager.getCurrentItem();

        if (b.getPages().get(current) instanceof BookPageText) {
            ((BookPageText) b.getPages().get(current)).setContentPageText(textContent);
        }
    }

    @Override
    public void newBookPageText() {
        int current = mBookViewPager.getCurrentItem();

        BookPageText bookPageText = new BookPageText();
        bookPageText.setContentPageText("");

        b.getPages().add(b.getPages().size() - 1, bookPageText);

        setIndicator(current + 1, b.getPages().size());
        mBookViewPagerAdapter.notifyDataSetChanged();

    }
}

Это код фрагмента

public class BookEditorFragment extends Fragment {

    private EditorFrToEditorActInterface mCallback;

    public interface EditorFrToEditorActInterface {
        void newBookPageText();
        void saveBookPageTextContent(String s);
     }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle pageContent = getArguments();
        if (pageContent != null) {
            page = pageContent.getParcelable("page");
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (page instanceof BookPageText) {
            BookPageText bookPage = (BookPageText) page;

            mView = inflater.inflate(R.layout.book_page_text_fragment, container, false);
            contentPage = (EditText) mView.findViewById(R.id.content_text);

            String contentPageText = bookPage.getContentPageText();
            contentPage.setText(contentPageText.isEmpty() ? "" : Html.fromHtml(contentPageText));

            contentPage.addTextChangedListener(new TextWatcher() {
                public void onTextChanged(CharSequence c, int start, int before, int count) {
                    mCallback.saveBookPageTextContent(c.toString());
                }

                public void beforeTextChanged(CharSequence c, int start, int count, int after) {
                }

                public void afterTextChanged(Editable c) {
                }
            });

        } 

        return mView;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            mCallback = (EditorFrToEditorActInterface) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement NewPageInterface");
        }
    }

    @Override
    public void onDetach() {
        mCallback = null;
        super.onDetach();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.editor_new_text:
                mCallback.newBookPageText();
            break;
        }
    }

}

Это код FragmentStatePagerAdapter.

public class BookViewPagerAdapter extends FragmentStatePagerAdapter {
    private ArrayList<Object> bookPages = new ArrayList<>();
    private final SparseArray<WeakReference<BookEditorFragment>> instantiatedFragments = new SparseArray<>();

    public BookViewPagerAdapter(FragmentManager fm, Book b) {
        super(fm);
        this.bookPages = b.getPages();
    }

    @Override
    public Fragment getItem(int position) {

        Object page = bookPages.get(position);

        Bundle pageContent = new Bundle();
        if (page instanceof BookPageText) {
            BookPageText bookPageText = (BookPageText) page;
            pageContent.putParcelable("page", bookPageText);
        } 

        BookEditorFragment fragment = new BookEditorFragment();
        fragment.setArguments(pageContent);
        return fragment;
    }

    @Override
    public int getCount() {
        return bookPages.size();
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final BookEditorFragment fragment = (BookEditorFragment) super.instantiateItem(container, position);
        instantiatedFragments.put(position, new WeakReference<>(fragment));
        return fragment;
    }

    @Override
    public void destroyItem(final ViewGroup container, final int position, final Object object) {
        instantiatedFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    @Nullable
    public Fragment getFragment(final int position) {
        final WeakReference<BookEditorFragment> wr = instantiatedFragments.get(position);
        if (wr != null) {
            return wr.get();
        } else {
            return null;
        }
    }

    @Override
    public int getItemPosition(Object object) {
        int position = bookPages.indexOf(object);
        return position == -1 ? POSITION_NONE : position;
    }
}

Из-за длины кода я удалил некоторые части, такие как onClickListener, onPageSelectionListener и другие типы страниц, которые я создаю прямо сейчас.

Проблема

Эта логика, кажется, работает правильно, но каждый раз, когда я изменяю содержимое EditText во фрагменте, закрывающий фрагмент слева также обновляется, и я не знаю, почему.

введите описание изображения здесь
Как вы можете видеть на изображении, если я напишу что-то в EditText2, то же самое содержимое появится в EditText1, и это не имеет смысла.

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

Мои попытки

1) Я пытался поймать onFocusChange вместо использования addTextChangedListener, но ничего не изменилось.

2) Я попытался реализовать другую логику, используя onChangePageListener(), но в этом случае я теряю mBookViewPager.getCurrentItem(), поэтому обновление идет неправильно.

3) Я пробовал все эти сообщения: one, два, три и четыре.

Как я могу исправить это странное поведение? Возможно ли, что проблема в том, как я ссылаюсь на страницы в ArrayList книги?

Спасибо


person michoprogrammer    schedule 10.06.2016    source источник
comment
Можете ли вы предоставить ссылку на ваш код. Его трудно воспроизвести с кодом, предоставленным вами   -  person Ankit Aggarwal    schedule 14.06.2016


Ответы (1)


Вот некоторые из возможных ошибок, которые я обнаружил в вашей реализации.

  1. управлять текущей позицией страницы

     mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
                @Override
                public void onPageSelected(int p) {
                current = p;
                Log.e("Postion", "" + p);
                }
    
                @Override
                public void onPageScrolled(int arg0, float arg1, int arg2) {}
    
                @Override
                public void onPageScrollStateChanged(int arg0) {}
            });
    
  2. viewpager автоматически загружает предыдущий и следующий вид, чтобы он не устанавливал пейджер OffscreenPageLimit, вызывая mathod

    mViewPager.setOffscreenPageLimit();
    
  3. всегда убедитесь, что если вы используете оператор if в адаптере, вы всегда должны помещать его встречную часть через оператор else даже для любого значения по умолчанию.

    if (page instanceof BookPageText) {
        BookPageText bookPageText = (BookPageText) page;
        pageContent.putParcelable("page", bookPageText);
    }
    
person RBK    schedule 14.06.2016
comment
Я внес те изменения, которые вы предложили, но ничего не изменилось... Возможно ли, что проблема в объекте модели? Я думал об этом, потому что для сохранения своей Книги я создал класс, который реализует Serializable, а внутри класса у меня есть ссылка на другой класс, который реализует Serializable и Parcelable. Каждый раз, когда я извлекаю и сохраняю книгу, она находится в/из файла. - person michoprogrammer; 16.06.2016
comment
да, может быть, вы можете передавать данные через EventBus вместо Serializable или Parcelable. если вы хотите сохранить эти данные, затем используйте Gson для преобразования вашей модели в строку и сохранения этой строки в предпочтениях, вы можете получить эту строку и преобразовать ее в объект модели с помощью Gson. - person RBK; 16.06.2016
comment
Начал вчера в новой ветке конвертацию в json версию и надеюсь это будет правильный выбор. Я не понимаю, где я могу использовать EventBus или зачем использовать EventBus вместо простого пакета. - person michoprogrammer; 16.06.2016
comment
простой пакет пройдет только тогда, когда произойдет системное событие, но с помощью eventBus вы можете определить свой собственный прослушиватель событий и передать объект любого класса без сериализации или приведения. - person RBK; 16.06.2016
comment
Мм, хорошо, я попробую ваше решение, может быть, оно решит мою проблему. Вы имеете в виду это? - person michoprogrammer; 16.06.2016