17

Sto utilizzando il pacchetto Android support.v4 per sviluppare un ViewPager contenente più Fragment s.I frammenti di ViewPager vengono distrutti nel tempo?

Sto cercando di nascondere le Visualizzazioni quando l'utente cambia pagina. Quindi, ho implementato un OnPageChangeListener per ascoltare il mio adattatore e chiamare un metodo update() nel mio Fragment s quando si verifica una modifica della pagina. Ma ricevo un NullPointerException e non riesco a capire perché.

Ecco il codice:

public class MyActivity extends FragmentActivity implements 
     OnPageChangeListener { 

    private static final int NUM_ITEMS = 2; 
    private ViewPager mPager; 
    private static SpaceAdapter mAdapter; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.fragment_pager); 

     mAdapter = new SpaceAdapter(getSupportFragmentManager()); 
     mPager = (ViewPager) findViewById(R.id.pager); 
     mPager.setAdapter(mAdapter); 

     mPager.setOnPageChangeListener(this); 
} 

    public static class SpaceAdapter extends FragmentPagerAdapter { 

     public SpaceAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public int getCount() { 
      return NUM_ITEMS; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      switch (position) { 
      case 0: 
      return new MyFragment(); 
      case 1: 
      return new MyFragment(); 
      default: 
      return new MyFragment(); 
      } 
     } 
    } 

    @Override 
    public void onPageScrollStateChanged(int arg0) { 
     Log.i("pagination", "scroll state changed: " + arg0); 
} 

    @Override 
    public void onPageScrolled(int arg0, float arg1, int arg2) { 
     // Log.i("pagination", "page scroll: " + arg0 + " with: " + arg1 + ", " + arg2); 
     if (mAdapter.getItem(arg0) instanceof IUpdateOnPage) { 
      ((IUpdateOnPage) mAdapter.getItem(arg0)).updateOnPage(); 
     } 
    } 

    @Override 
    public void onPageSelected(int arg0) { 
     Log.i("pagination", "page selected: " + arg0); 
    } 
} 

e

public class MyFragment extends Fragment implements 
     SurfaceHolder.Callback, IUpdateOnPage { 

    private SurfaceView charts; 

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

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View v = inflater.inflate(R.layout.crew, null); 
     bindViews(v); 
     return v; 
    } 

    private void bindViews(View v) { 
     charts = (SurfaceView) v.findViewById(R.id.civ_charts); 

     charts.getHolder().addCallback(this); 
     Log.i("wtf", "huh " + String.valueOf(charts == null)); // logs false 
    } 

    @Override 
    public void updateOnPage() { 
     if (charts != null) { 
      Log.i("crew surface", "hidden"); 
      charts.setVisibility(View.GONE); 
     } else { 
      Log.i("crew surface", "charts is null"); //THIS HERE gets logged 
     } 
    } 
} 

wQuando copio/incollato ho rimosso i SurfaceHolder.Callback metodi, ma ci sono. Il metodo bindViews(v) registra se charts == null e che restituisce sempre false. Alla pagina I, viene chiamato updateOnPage e charts == null restituisce true. Perché succede questo e come faccio a girarlo?

e questa è la linea 108:

charts.setVisibility(View.GONE); 
+0

ok, dopo ulteriori indagini, presumo che il frammento venga distrutto all'inizio dell'impaginazione (anche se la vista rimane?). quando si scorre, posso ancora vedere "metà" del frammento fino a quando il nuovo frammento non scatta a piena vista. Quindi, se tutti i riferimenti vengono raccolti e tutto ciò che rimane è la vista, come posso fare questo? – edthethird

+0

se stai ricevendo un 'NullPointerException', puoi pubblicare l'output logcat? –

+0

beh, in realtà lo sto prendendo in modo che non venga generata un'eccezione. Il problema è 'charts.setVisibility (View.GONE);'. i grafici sono nulli. È alla fine del secondo campione di codice, proprio sopra il 'else'. Aggiunto traccia dello stack. – edthethird

risposta

33

Aggiungere il seguente quando si inizializza il vostro ViewPager,

mPager.setOffscreenPageLimit(NUM_ITEMS-1); 

Nel vostro caso, questo imposterà il numero di pagine off-schermo a 1 (cioè manterrà la pagina fuori campo aggiuntiva in memoria quando l'altra pagina è attualmente a fuoco). Questo costringerà il tuo ViewPager a mantenere tutti gli Fragment s anche quando non sono a fuoco.

+0

che ha risolto un altro problema di prestazioni minori che stavo avendo così grazie! Ma si blocca ancora quando questo frammento viene mostrato con lo stesso puntatore nullo .. – edthethird

+0

in realtà, che risolve il problema principale. Non ho più bisogno di chiamare setVisibilty (View.gone). Strano, ma grazie!Giusto per chiarire ... il SurfaceView non stava paginando correttamente, è rimasto su tutte le pagine anche quando ho fatto scorrere il dito. – edthethird

+0

Questo è strano perché "setOffscreenPageLimit' è impostato su 1 (e NUM_ITEMS - 1 equivale a 1) nella v4, ma sono contento che il tuo problema sia stato risolto. – louielouie

4

Ho esaminato il tuo codice e penso che il problema sia che in onPageScrolled, stai chiamando getItem. Questa implementazione (che in realtà è come la maggior parte delle implementazioni sul Web) restituisce ogni volta una nuova istanza. Tuttavia, la maggior parte degli esempi che ho visto non chiama lo getItem, quindi di solito è tutto a posto.

Nel tuo caso, vorrei tenere pigramente creare il frammento in getItem: se non esiste per quella posizione, quindi creare, e poi appendere su di esso in una collezione ArrayList o qualche altro, ma se esiste già , basta restituirlo da quella raccolta.

Altrimenti, si crea un'istanza di frammento A, quindi si scorre su un'altra istanza di frammento B. Si tenta di dire all'istanza di frammento A di pulire alcune viste, ma si finisce col dire a una nuova istanza di frammento C di farlo. Non ha ancora avuto la possibilità di impostare le proprie visualizzazioni, quindi stai ottenendo il puntatore nullo ai grafici.

+0

oh questo è un buon punto. Ho ottenuto questa implementazione da un campione google da qualche parte, ma indagherò sull'implementazione di un array o qualcosa per mantenere i frammenti. Grazie! – edthethird