7

Introduzionedi Save/Aggiornamento Frammento dati EditText in un FragmentStatePagerAdapter

ho un'attività con un libro che contiene un ArrayList di tipo "pagina" e per gestire tutte le pagine che ho deciso di utilizzare un FragmentStatePagerAdapter in cui si del mio frammento contiene una pagina.

Ho creato un'interfaccia per la comunicazione tra ogni frammento nel cercapersone e l'attività padre. Il metodo di cui ho bisogno in questa interfaccia è per l'aggiornamento di una pagina mostrata in un frammento, quindi ho implementato l'attività padre, l'interfaccia per ricevere i dati da un frammento e memorizzarli in una pagina per salvarli nell'array.

Ogni frammento ha un EditText in cui l'utente può scrivere e ho impostato un addTextChangedListener per catturare il momento in cui l'utente si ferma a scrivere. Quando l'utente si ferma a scrivere in EditText, in onTextChanged(), chiamo la funzione implementata nel padre dell'attività.

Questo è il mio codice di attività

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(); 

    } 
} 

Questo è il frammento di codice

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; 
     } 
    } 

} 

Questo è il codice 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; 
    } 
} 

A causa della lunghezza del codice ho rimosso alcune parti come onClickListener, onPageSelectionListener e altri tipi di pagine che sto creando correttamente adesso.

Il problema

Questa logica sembra funzionare correttamente, ma ogni volta che modifico il contenuto di un EditText in un frammento, il frammento vicino alla sinistra viene aggiornato e non so perché.

enter image description here
Come si può vedere nell'immagine, se scrivo qualcosa nel EditText2, lo stesso contenuto apparirà nel EditText1 e questo non ha senso.

Un altro problema è quando aggiungo una nuova pagina nel libro, la pagina è creata correttamente, ma con il contenuto della pagina precedente e questo non ha senso. (Di nuovo!)

I miei tentativi

1) Ho cercato di prendere l'onFocusChange invece di utilizzare l'addTextChangedListener, ma non è cambiato nulla.

2) Ho provato a implementare una logica diversa utilizzando lo onChangePageListener(), ma in questo caso perdo lo mBookViewPager.getCurrentItem() in modo che l'aggiornamento non funzioni.

3) Ho provato questo tutti i post: one, two, three e four.

Come posso correggere questo strano comportamento? È possibile che il problema sia nel modo in cui faccio riferimento alle pagine nell'ArrayList del libro?

Grazie

+0

può fornire link al tuo codice. È difficile da replicare con il codice fornito da te –

risposta

0

Alcuni dei possibili errori che ho trovato nella tua implemantation sono.

  1. di gestire pagina corrente posetion implementare

    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 caricare automaticamente privious e accanto vista per privent ha fissato cercapersone OffscreenPageLimit chiamando mathod

    mViewPager.setOffscreenPageLimit(); 
    
  3. sempre fare in modo che se si utilizza l'istruzione if nell'adattatore, è necessario impostare la parte del contatore sempre vi una dichiarazione else anche per qualsiasi valore predefinito.

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

Ho apportato le modifiche proposte ma non è cambiato nulla ... È possibile che il problema sia nell'oggetto del modello? Ci stavo pensando perché per aver salvato il mio libro ho creato una classe che implementa "Serializable" e all'interno della classe ho un riferimento a un'altra classe che implementa "Serializable" e "Parcelable". Ogni volta che recupero e salvo un libro è in/from file. – michoprogrammer

+0

sì, potrebbe essere il caso, è possibile passare i dati tramite EventBus anziché Serializable o Parcelable. se si desidera archiviare tali dati, quindi utilizzare Gson per convertire il modello in stringa e memorizzare tale stringa in base alle proprie preferenze, è possibile recuperare tale stringa e convertirla nell'oggetto modello mediante Gson. – RBK

+0

Ho iniziato ieri in una nuova filiale la conversione in una versione JSON e spero che questa sia la scelta giusta. Non capisco dove posso usare EventBus o perché utilizzare EventBus invece di un semplice pacchetto. – michoprogrammer

Problemi correlati