6

EDYCJA: Okazało się, że działanie zapisuje instancję, ale dane zapisane w Fragmentach nie są zapisywane w Aktywności savedInstanceState. Zapisuję bieżący czas w outState, ale nie jest on na tyle zaawansowany, ponieważ działanie nie ma w swoim SavedInstanceState nic na czas i zwraca 'null' na czas, jeśli wydrukuję go do logcat .. ..FragmentPagerAdapter nie przywraca fragmentów po zmianie orientacji

Buduję aplikację, która ma wbudowany zegar odliczający i odliczający. Podstawową czynnością hostingu dla timerów jest funkcja FragmentActivity, w której znajduje się FroughtPagerAdapter, który nadyma dwa fragmenty w kodzie (nie podaję identyfikatora do fragmentów w XML, ponieważ nie są one zdefiniowane jako fragmenty w .xml). Wszystko działa świetnie, dopóki nie zmieni się orientacja, a potem aktywność wygląda na to, że traci kontakt ze starymi fragmentami i po prostu wybiera tworzenie nowych. Oznacza to, że wszelkie bieżące odliczanie zostanie utracone, a wybrany czas również zostanie utracony po zmianie konfiguracji. Będę musiał kontynuować liczenie (jeśli się zaczęło) i wszystkie aktualnie wyświetlane liczby ...

Wiem, że adapter ma za zadanie radzić sobie z tymi rzeczami samodzielnie, a ja ustawiam SetRetainInstance (true) zarówno w OnCreate, jak i OnCreateView.

Wstawiam haczyki do kodu Fragmentu, aby dać mi znać, gdy wartość saveInstanceState NIE jest zerowa, więc przynajmniej wiem, co się dzieje, ale wygląda na to, że instancja jest zawsze NULL i tworzy od zera ... zawsze.

Kilka innych rozwiązań powoduje, że nadpisuję instantiateItem, ale wygląda na to, że jest używany tylko do resetowania callbacków, inni zmieniają ustawienia w Manifestu (nie widzą). Inne rozwiązania wyglądają tak, jakbym miał Ustaw się dobrze ... ale oczywiście, coś mi przeszkadza po drodze. Podaję tylko kod FragmentActivity, FragementPagerAdapter i fragment kodu Fragmentu, ponieważ nie chcę spamować posta z kodem, który może nie być problemem.

FragmentActivity

public class Timer_Main extends FragmentActivity { 
    ViewPager pager; 
    Timer_Pager mAdapter; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.timer_pager); 

     mAdapter = new Timer_Pager(this, getSupportFragmentManager()); 

     pager = (ViewPager) findViewById(R.id.timer_pager_display); 
     pager.setAdapter(mAdapter); 

    } 

    public static String getTitle(Context ctxt, int position) { 
       // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     outState.putInt("pageItem", pager.getCurrentItem()); 

    } 

    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) { 
     super.onRestoreInstanceState(savedInstanceState); 

    } 
}  

FragementPagerAdapter

public class Timer_Pager extends FragmentPagerAdapter{ 
    Context ctxt = null; 
    public Timer_Pager(Context ctxt, FragmentManager fm) { 
     super(fm); 
     this.ctxt = ctxt; 
     } 


    @Override 
    public Fragment getItem(int position) { 

     switch (position) { 
     case 0: { 
      return(Countdown_Fragment.newInstance()); 
     } 
     case 1: 
      return(Countup_Fragment.newInstance()); 
     } 
     return null; 
    } 

    @Override 
    public String getPageTitle(int position) { 

     switch (position) { 
     case 0: 
      return(String.format(ctxt.getString(R.string.Countdown_label))); 
     case 1: 
      return(String.format(ctxt.getString(R.string.Countup_label))); 
     } 
     return null; 
    } 

    @Override 
    public int getCount() { 
     // doing only three pages, right now...one for countdown, one for countup,   and one for Tabata. 
     return 2; 
    } 

    private static String makeFragmentName(int viewId, int position) 
    { 
     return "android:switcher:" + viewId + ":" + position; 
    } 
}  

fragment zawiera nieco więcej kodu w nim, więc będę wcisnąć tylko to, co powinno być istotą problemu ... .Jeśli potrzebne jest więcej, podzielę go.

public class Countdown_Fragment extends Fragment implements OnClickListener { 
    Calendar CountdownTime = Calendar.getInstance(); 
    static AutoResizeTextView tv; 
    static ImageButton HoursUp; 
    static ImageButton HoursDown; 
    static ImageButton MinutesUp; 
    static ImageButton MinutesDown; 
    static ImageButton SecondsUp; 
    static ImageButton SecondsDown; 
    static ImageButton Reset; 
    static ImageButton StartPausecount; 
    static ImageButton Stopcount; 
    static Boolean Arewecounting = false; 
    static Boolean Arewecountingdown = false; 
    static AutoResizeTextView ThreetwooneGO; 
    static MyCountdownTimer Countdown_Timer_Activity; 
    ThreetwooneCount Start_countdown; 
    static Long MillstoPass; 

    static Countdown_Fragment newInstance() { 

     Countdown_Fragment frag = new Countdown_Fragment(); 
     return (frag); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 

     outState.putString("CurrentTimer", (String) tv.getText()); 
     Log.v("status", "saved fragment state" + tv.getText()); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 

    } 

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

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 

      setRetainInstance(true); 
      View result = inflater.inflate(R.layout.countdown_timer_layout, 
       container, false); 
     tv = (AutoResizeTextView) result.findViewById(R.id.timer_textview); 
     tv.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View arg0) { 
       new TimePickerDialog(getActivity(), t, 0, 0, true).show(); 
      } 
     }); 
     if (savedInstanceState != null) { 
      Log.v("status", "fragment is NOT empty"); 
      tv.setText(savedInstanceState.getString("CurrentTimer", 
        tv.toString())); 
     } else { 
      Log.v("status", "fragment is empty"); 
     // tv.setText("00:00:00"); 

     } 
     tv.resizeText(); 

     ThreetwooneGO = (AutoResizeTextView) result 
       .findViewById(R.id.timer_countdown_text); 

     HoursUp = (ImageButton) result.findViewById(R.id.hours_up); 
     HoursDown = (ImageButton) result.findViewById(R.id.hours_down); 
     MinutesUp = (ImageButton) result.findViewById(R.id.minutes_up); 
     MinutesDown = (ImageButton) result.findViewById(R.id.minutes_down); 
     SecondsUp = (ImageButton) result.findViewById(R.id.seconds_up); 
     SecondsDown = (ImageButton) result.findViewById(R.id.seconds_down); 
     Reset = (ImageButton) result.findViewById(R.id.reset); 
     StartPausecount = (ImageButton) result 
       .findViewById(R.id.startpausecount); 
     Stopcount = (ImageButton) result.findViewById(R.id.stopcount); 

     HoursUp.setOnClickListener(this); 
     HoursDown.setOnClickListener(this); 
     SecondsUp.setOnClickListener(this); 
     SecondsDown.setOnClickListener(this); 
     MinutesUp.setOnClickListener(this); 
     MinutesDown.setOnClickListener(this); 
     Reset.setOnClickListener(this); 
     StartPausecount.setOnClickListener(this); 
     Stopcount.setOnClickListener(this); 

     return (result); 
    } 

    public void chooseTime(View v) { 
     new TimePickerDialog(getActivity(), t, 0, 0, true).show(); 
    } 

    TimePickerDialog.OnTimeSetListener t = new TimePickerDialog.OnTimeSetListener() { 
     public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 
      CountdownTime.set(Calendar.HOUR_OF_DAY, hourOfDay); 
      CountdownTime.set(Calendar.MINUTE, minute); 
      CountdownTime.set(Calendar.SECOND, 0); 
      CountdownTime.set(Calendar.MILLISECOND, 0); 

      updateLabel(); 
     } 
    }; 

    private void updateLabel() { 

     String entiretime; 
     entiretime = String.format("%tT", CountdownTime); 
     tv.setText(entiretime); 
    } 

Oto mój zegar, którego używam w Coun tdown ....

public class MyCountdownTimer { 

private long millisInFuture; 
private long countDownInterval; 
Countdown_Fragment ctxt; 
AutoResizeTextView Timer_edit; 
private volatile boolean IsStopped = false; 

public MyCountdownTimer(long pMillisInFuture, long pCountDownInterval, 
     AutoResizeTextView Artv) { 
    this.millisInFuture = pMillisInFuture; 
    this.countDownInterval = pCountDownInterval; 

    Timer_edit = Artv; 

} 

public void Start() { 

    final Handler handler = new Handler(); 
    final Runnable counter = new Runnable() { 

     public void run() { 
      if (IsStopped == false) { 
       if (millisInFuture <= 0) { 
        Countdown_Fragment.done_counting(); 
       } else { 
        long sec = millisInFuture/1000; 
        Timer_edit.setText(String.format("%02d:%02d:%02d", 
          sec/3600, (sec % 3600)/60, (sec % 60))); 
        millisInFuture -= countDownInterval; 
        handler.postDelayed(this, countDownInterval); 
       } 
      } 
     } 
    }; 

    handler.postDelayed(counter, countDownInterval); 
} 

public void Cancel() { 
    IsStopped = true; 
    Timer_edit = null; 
    Log.v("status", "Main Timer cancelled"); 
    // this.ctxt = null; 

} 
public long whatisourcount(){ 
    return(millisInFuture); 
} 
} 

Odpowiedz

4

Jak się okazuje, RetainInstance było przyczyną konfliktu między nią a ViewPager/zasilacz/FragmentManager robi swoje rzeczy. Usunięcie go spowodowało, że Pager poprawnie przebudował Fragment, w tym TextView I, gdzie wcześniej nie był. Zaczynam także otrzymywać pakiet w OnCreateView, gdzie zawsze był on zerowy z ustawieniem RetainInstance na True.

Musiałem usunąć RetainInstance i wykorzystać OnSaveInstanceState i OnCreateView, aby przekazać bieżący status Fragmentu, zanim został zniszczony, a następnie odtworzyć go w OnCreateView, aby zresetować Fragment do stanu sprzed jego zniszczenia.

Miałem nadzieję, że Runnable, którego używałem do odliczania, przetrwają, lub będę w stanie go ponownie podłączyć, ale nie mogłem znaleźć sposobu. Musiałem zapisać bieżącą liczbę w milisekundach i wrócić do Fragmentu, aby kontynuować od miejsca, w którym zostało przerwane.To nie jest wielka sprawa, ale jestem ciekawy, czy naprawdę możesz przywiązać te wszystkie rzeczy. Runnable DOES nadal są kontynuowane po zmianie konfiguracji, ale nie aktualizuje niczego w interfejsie użytkownika, więc próbuję anulować wywołania zwrotne i anulować je, gdy jestem w stanie OnSaveInstanceState.

Czytam również pozycje, w których potrzebuję tylko RetainInstance dla przedmiotów, które mają dołączone AsyncTask lub inny podobny element ... w przeciwnym razie po prostu odbuduj go wewnątrz kodu.

+0

Witam .. Mam podobny problem. Czy istnieje sposób na zachowanie ustawionej instancji true i sprawdzenie, czy działa, ponieważ w przeciwnym razie powinienem napisać całą moją logikę. Z góry dziękuję :) – jaffa

+0

Nie mogłem znaleźć sposobu na obejście –

+0

http://stackoverflow.com/questions/6976027/reusing-fragments-in-a-fragmentpageradapter/29287415#29287415 –