EDIT: I found out that the Activity is saving the instance, but the Fragments saved data is not making it up to the Activity savedInstanceState. I'm saving the current time in the outState, but its not making its way all the way up, as the activity has nothing in its SavedInstanceState for the time and returns 'null' for the time if I print it to the logcat....
I am building an application that has the a countup and countdown timer built in. The basic hosting activity for the timers is a FragmentActivity which hosts a FragementPagerAdapter that inflates two fragments within the code (I do not give an id to the fragments within the XML as they are not defined as fragments within the .xml). Everything works great until an orientation change and then the activity looks like it looses contact with the old fragments and just chooses to create new ones. This means that any current countdown is lost and any time chosen is also lost upon configuration change. I will need to keep the count going (if its started) and any numbers currently displayed....
I know that the Adapter is supposed to handle these things on its own, and I'm setting the SetRetainInstance(true) in both the OnCreate and OnCreateView.
I put in hooks into the Fragment code to let me know whenever the saveInstanceState is NOT null so at least I know what is going on, but it seems like the instance is always NULL, and it creates from scratch...always.
Some other solutions have me overriding the instantiateItem, but it seems that its is only used for getting callbacks reset, others changing a setting in the Manifest(frowned upon).... Other solutions look to me like I have things setup right...but obviously, I'm messing something up along the way. I'm only giving code for the FragmentActivity, FragementPagerAdapter, and a bit of the Fragment code as I don't want to spam the post with code that may not be the issue.
The 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);
}
}
The 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;
}
}
The Fragment has a bit more code in it, so I'll push in just what should be the core of the problem....if more is needed, I'll splice it in.
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);
}
Here is my timer that I'm using for Countdown....
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);
}
}