在 FragmentStatePagerAdapter 中保存/更新片段的 EditText 数据

7

介绍

我有一个包含类型为“page”的arraylist的书籍活动,并决定使用FragmentStatePagerAdapter来处理所有页面,其中我的一个片段包含一页。

我为每个pager中的片段与父活动之间的通信创建了一个接口。我需要此接口中的方法来更新在片段中显示的页面,因此我实现了父活动对接收来自片段的数据并将其存储在一个页面中以保存在arraylist中的接口。

每个片段都有一个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的内容时,左侧的关闭片段也会更新,我不知道为什么。

enter image description here
如你所见,在图像中,如果我在EditText2中写入内容,同样的内容将出现在EditText1中,这毫无意义。

另一个问题是,当我添加新页面到书中时,页面被正确创建,但内容却与上一页相同,这毫无意义。(再一次!)

我的尝试

1)我尝试捕获onFocusChange而不是使用addTextChangedListener,但没有任何变化。

2)我尝试实现不同的逻辑,使用onChangePageListener(),但在这种情况下,我丢失了mBookViewPager.getCurrentItem(),所以更新出错了。

3) 我尝试了所有这些帖子:one, two, threefour

我应该如何纠正这种奇怪的行为呢? 可能是我在书籍的ArrayList中引用页面的方式有问题吗?

谢谢


你能提供你代码的链接吗?你提供的代码难以复制。 - Ankit Aggarwal
1个回答

0

我在你的实现中发现了一些可能的错误。

  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

    mViewPager.setOffscreenPageLimit();
    
  3. 始终确保在适配器中使用if语句时,即使是对于任何默认值,也应该通过else语句放置其对应的部分。

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

我按照你提出的更改进行了修改,但是没有任何变化...问题可能在模型对象中吗?我正在考虑这个问题,因为为了保存我的书,我创建了一个实现“Serializable”的类,并且在该类内部引用了另一个实现“Serializable”和“Parcelable”的类。每次我从文件中检索和保存一本书。 - michoprogrammer
是的,这是可能的。你可以通过EventBus传递数据,而不是使用Serializable或Parcelable。 如果你想要存储这些数据,那么可以使用Gson将你的模型转换为字符串并将该字符串存储到偏好设置中,然后可以检索该字符串并使用Gson将其转换为模型对象。 - RBK
我昨天开始在一个新的分支上进行转换为JSON版本的工作,希望这是正确的选择。我不知道在哪里可以使用EventBus,或者为什么要使用EventBus而不是简单的bundle。 - michoprogrammer
一个简单的捆绑只有在系统事件发生时才会通过,但是使用EventBus,您可以定义自己的自定义事件监听器,并传递任何类的对象,而无需序列化或可序列化。 - RBK
嗯,好的,我会尝试你的解决方案,也许它可以解决我的问题。你是指这个吗? - michoprogrammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接