In ChartFragment, MapFragment, StatsFragment, for callbacks from

TrackDataHub, check that the fragment is resumed.
In any runnable executed on the UI thread, also check
that the fragment is resumed.
This commit is contained in:
Jimmy Shih
2012-08-24 12:46:11 -07:00
parent 2c87df6d75
commit c6861d1e49
3 changed files with 220 additions and 166 deletions
@@ -83,7 +83,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
private final Runnable updateChart = new Runnable() { private final Runnable updateChart = new Runnable() {
@Override @Override
public void run() { public void run() {
if (trackDataHub == null) { if (!isResumed() || trackDataHub == null) {
return; return;
} }
@@ -178,111 +178,141 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onTrackUpdated(Track track) { public void onTrackUpdated(Track track) {
if (track == null || track.getTripStatistics() == null) { if (isResumed()) {
startTime = -1L; if (track == null || track.getTripStatistics() == null) {
return; startTime = -1L;
return;
}
startTime = track.getTripStatistics().getStartTime();
} }
startTime = track.getTripStatistics().getStartTime();
} }
@Override @Override
public void clearTrackPoints() { public void clearTrackPoints() {
tripStatisticsBuilder = startTime != -1L ? new TripStatisticsBuilder(startTime) : null; if (isResumed()) {
pendingPoints.clear(); tripStatisticsBuilder = startTime != -1L ? new TripStatisticsBuilder(startTime) : null;
chartView.reset(); pendingPoints.clear();
chartView.reset();
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
chartView.resetScroll(); if (isResumed()) {
} chartView.resetScroll();
}); }
}
});
}
} }
@Override @Override
public void onSampledInTrackPoint(Location location) { public void onSampledInTrackPoint(Location location) {
double[] data = new double[ChartView.NUM_SERIES + 1]; if (isResumed()) {
fillDataPoint(location, data); double[] data = new double[ChartView.NUM_SERIES + 1];
pendingPoints.add(data); fillDataPoint(location, data);
pendingPoints.add(data);
}
} }
@Override @Override
public void onSampledOutTrackPoint(Location location) { public void onSampledOutTrackPoint(Location location) {
fillDataPoint(location, null); if (isResumed()) {
fillDataPoint(location, null);
}
} }
@Override @Override
public void onSegmentSplit(Location location) { public void onSegmentSplit(Location location) {
fillDataPoint(location, null); if (isResumed()) {
fillDataPoint(location, null);
}
} }
@Override @Override
public void onNewTrackPointsDone() { public void onNewTrackPointsDone() {
chartView.addDataPoints(pendingPoints); if (isResumed()) {
pendingPoints.clear(); chartView.addDataPoints(pendingPoints);
getActivity().runOnUiThread(updateChart); pendingPoints.clear();
getActivity().runOnUiThread(updateChart);
}
} }
@Override @Override
public void clearWaypoints() { public void clearWaypoints() {
chartView.clearWaypoints(); if (isResumed()) {
chartView.clearWaypoints();
}
} }
@Override @Override
public void onNewWaypoint(Waypoint waypoint) { public void onNewWaypoint(Waypoint waypoint) {
if (waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) { if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
chartView.addWaypoint(waypoint); chartView.addWaypoint(waypoint);
} }
} }
@Override @Override
public void onNewWaypointsDone() { public void onNewWaypointsDone() {
getActivity().runOnUiThread(updateChart); if (isResumed()) {
getActivity().runOnUiThread(updateChart);
}
} }
@Override @Override
public boolean onMetricUnitsChanged(boolean metric) { public boolean onMetricUnitsChanged(boolean metric) {
if (metricUnits == metric) { if (isResumed()) {
return false; if (metricUnits == metric) {
} return false;
metricUnits = metric;
chartView.setMetricUnits(metricUnits);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
chartView.requestLayout();
} }
}); metricUnits = metric;
return true; chartView.setMetricUnits(metricUnits);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
chartView.requestLayout();
}
}
});
return true;
}
return false;
} }
@Override @Override
public boolean onReportSpeedChanged(boolean speed) { public boolean onReportSpeedChanged(boolean speed) {
if (reportSpeed == speed) { if (isResumed()) {
return false; if (reportSpeed == speed) {
} return false;
reportSpeed = speed;
chartView.setReportSpeed(reportSpeed);
boolean chartShowSpeed = PreferencesUtils.getBoolean(
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT);
setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed);
setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
chartView.requestLayout();
} }
}); reportSpeed = speed;
return true; chartView.setReportSpeed(reportSpeed);
boolean chartShowSpeed = PreferencesUtils.getBoolean(
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT);
setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed);
setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
chartView.requestLayout();
}
}
});
return true;
}
return false;
} }
@Override @Override
public boolean onMinRecordingDistanceChanged(int value) { public boolean onMinRecordingDistanceChanged(int value) {
if (minRecordingDistance == value) { if (isResumed()) {
return false; if (minRecordingDistance == value) {
return false;
}
minRecordingDistance = value;
return true;
} }
minRecordingDistance = value; return false;
return true;
} }
/** /**
@@ -436,12 +466,12 @@ public class ChartFragment extends Fragment implements TrackDataListener {
} else { } else {
timeOrDistance = tripStatistics.getTotalTime(); timeOrDistance = tripStatistics.getTotalTime();
} }
elevation = tripStatisticsBuilder.getSmoothedElevation(); elevation = tripStatisticsBuilder.getSmoothedElevation();
if (!metricUnits) { if (!metricUnits) {
elevation *= UnitConversions.M_TO_FT; elevation *= UnitConversions.M_TO_FT;
} }
speed = tripStatisticsBuilder.getSmoothedSpeed() * UnitConversions.MS_TO_KMH; speed = tripStatisticsBuilder.getSmoothedSpeed() * UnitConversions.MS_TO_KMH;
if (!metricUnits) { if (!metricUnits) {
speed *= UnitConversions.KM_TO_MI; speed *= UnitConversions.KM_TO_MI;
@@ -275,93 +275,104 @@ public class MapFragment extends Fragment
@Override @Override
public void onLocationStateChanged(LocationState state) { public void onLocationStateChanged(LocationState state) {
final String message; if (isResumed()) {
final boolean isGpsDisabled; final String message;
if (!isSelectedTrackRecording()) { final boolean isGpsDisabled;
message = null; if (!isSelectedTrackRecording()) {
isGpsDisabled = false; message = null;
} else { isGpsDisabled = false;
switch (state) { } else {
case DISABLED: switch (state) {
String setting = getString( case DISABLED:
GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings String setting = getString(
: R.string.gps_location_access); GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings
message = getString(R.string.gps_disabled, setting); : R.string.gps_location_access);
isGpsDisabled = true; message = getString(R.string.gps_disabled, setting);
break; isGpsDisabled = true;
case NO_FIX: break;
message = getString(R.string.gps_wait_for_signal); case NO_FIX:
isGpsDisabled = false; message = getString(R.string.gps_wait_for_signal);
break; isGpsDisabled = false;
case BAD_FIX: break;
message = getString(R.string.gps_wait_for_better_signal); case BAD_FIX:
isGpsDisabled = false; message = getString(R.string.gps_wait_for_better_signal);
break; isGpsDisabled = false;
case GOOD_FIX: break;
message = null; case GOOD_FIX:
isGpsDisabled = false; message = null;
break; isGpsDisabled = false;
default: break;
throw new IllegalArgumentException("Unexpected state: " + state); default:
} throw new IllegalArgumentException("Unexpected state: " + state);
}
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (message != null) {
messageTextView.setText(message);
messageTextView.setVisibility(View.VISIBLE);
if (isGpsDisabled) {
Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
// Click to show the location source settings
messageTextView.setOnClickListener(MapFragment.this);
} else {
messageTextView.setOnClickListener(null);
}
} else {
messageTextView.setVisibility(View.GONE);
} }
} }
}); getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
if (message == null) {
messageTextView.setVisibility(View.GONE);
return;
}
messageTextView.setText(message);
messageTextView.setVisibility(View.VISIBLE);
if (isGpsDisabled) {
Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
// Click to show the location source settings
messageTextView.setOnClickListener(MapFragment.this);
} else {
messageTextView.setOnClickListener(null);
}
}
}
});
}
} }
@Override @Override
public void onLocationChanged(Location location) { public void onLocationChanged(Location location) {
currentLocation = location; if (isResumed()) {
updateCurrentLocation(); currentLocation = location;
updateCurrentLocation();
}
} }
@Override @Override
public void onHeadingChanged(double heading) { public void onHeadingChanged(double heading) {
if (mapOverlay.setHeading((float) heading)) { if (isResumed()) {
mapView.postInvalidate(); if (mapOverlay.setHeading((float) heading)) {
mapView.postInvalidate();
}
} }
} }
@Override @Override
public void onSelectedTrackChanged(final Track track) { public void onSelectedTrackChanged(final Track track) {
getActivity().runOnUiThread(new Runnable() { if (isResumed()) {
@Override getActivity().runOnUiThread(new Runnable() {
public void run() { @Override
boolean hasTrack = track != null; public void run() {
mapOverlay.setTrackDrawingEnabled(hasTrack); if (isResumed()) {
boolean hasTrack = track != null;
mapOverlay.setTrackDrawingEnabled(hasTrack);
if (hasTrack) { if (hasTrack) {
synchronized (this) { synchronized (this) {
/* /*
* Synchronize to prevent race condition in changing markerTrackId * Synchronize to prevent race condition in changing
* and markerId variables. * markerTrackId and markerId variables.
*/ */
currentSelectedTrackId = track.getId(); currentSelectedTrackId = track.getId();
updateMap(track); updateMap(track);
}
mapOverlay.setShowEndMarker(!isSelectedTrackRecording());
}
mapView.invalidate();
} }
mapOverlay.setShowEndMarker(!isSelectedTrackRecording());
} }
mapView.invalidate(); });
} }
});
} }
@Override @Override
@@ -371,12 +382,16 @@ public class MapFragment extends Fragment
@Override @Override
public void clearTrackPoints() { public void clearTrackPoints() {
mapOverlay.clearPoints(); if (isResumed()) {
mapOverlay.clearPoints();
}
} }
@Override @Override
public void onSampledInTrackPoint(Location location) { public void onSampledInTrackPoint(Location location) {
mapOverlay.addLocation(location); if (isResumed()) {
mapOverlay.addLocation(location);
}
} }
@Override @Override
@@ -386,22 +401,28 @@ public class MapFragment extends Fragment
@Override @Override
public void onSegmentSplit(Location location) { public void onSegmentSplit(Location location) {
mapOverlay.addSegmentSplit(); if (isResumed()) {
mapOverlay.addSegmentSplit();
}
} }
@Override @Override
public void onNewTrackPointsDone() { public void onNewTrackPointsDone() {
mapView.postInvalidate(); if (isResumed()) {
mapView.postInvalidate();
}
} }
@Override @Override
public void clearWaypoints() { public void clearWaypoints() {
mapOverlay.clearWaypoints(); if (isResumed()) {
mapOverlay.clearWaypoints();
}
} }
@Override @Override
public void onNewWaypoint(Waypoint waypoint) { public void onNewWaypoint(Waypoint waypoint) {
if (waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) { if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
// TODO: Optimize locking inside addWaypoint // TODO: Optimize locking inside addWaypoint
mapOverlay.addWaypoint(waypoint); mapOverlay.addWaypoint(waypoint);
} }
@@ -409,7 +430,9 @@ public class MapFragment extends Fragment
@Override @Override
public void onNewWaypointsDone() { public void onNewWaypointsDone() {
mapView.postInvalidate(); if (isResumed()) {
mapView.postInvalidate();
}
} }
@Override @Override
@@ -58,10 +58,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
// A runnable to update the total time field. // A runnable to update the total time field.
private final Runnable updateTotalTime = new Runnable() { private final Runnable updateTotalTime = new Runnable() {
public void run() { public void run() {
FragmentActivity activity = getActivity(); if (isResumed() && isSelectedTrackRecording() && !isSelectedTrackPaused()
if (activity != null && lastTripStatistics != null && isSelectedTrackRecording() && lastTripStatistics != null) {
&& !isSelectedTrackPaused()) { StatsUtils.setTotalTimeValue(getActivity(), System.currentTimeMillis()
StatsUtils.setTotalTimeValue(activity, System.currentTimeMillis()
- lastTripStatistics.getStopTime() + lastTripStatistics.getTotalTime()); - lastTripStatistics.getStopTime() + lastTripStatistics.getTotalTime());
} }
} }
@@ -74,11 +73,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void run() { public void run() {
Log.d(TAG, "UI update thread started"); Log.d(TAG, "UI update thread started");
while (isSelectedTrackRecording()) { while (isResumed() && isSelectedTrackRecording()) {
FragmentActivity activity = getActivity(); getActivity().runOnUiThread(updateTotalTime);
if (activity != null) {
activity.runOnUiThread(updateTotalTime);
}
try { try {
Thread.sleep(1000L); Thread.sleep(1000L);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -121,12 +117,13 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onLocationStateChanged(LocationState state) { public void onLocationStateChanged(LocationState state) {
if (isResumed() && state != LocationState.GOOD_FIX) { if (isResumed() && state != LocationState.GOOD_FIX) {
final FragmentActivity activity = getActivity(); getActivity().runOnUiThread(new Runnable() {
activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
lastLocation = null; if (isResumed()) {
StatsUtils.setLocationValues(activity, lastLocation, true); lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
}
} }
}); });
} }
@@ -135,17 +132,18 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onLocationChanged(final Location location) { public void onLocationChanged(final Location location) {
if (isResumed()) { if (isResumed()) {
final FragmentActivity activity = getActivity(); getActivity().runOnUiThread(new Runnable() {
activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (isSelectedTrackRecording() && !isSelectedTrackPaused()) { if (isResumed()) {
lastLocation = location; if (isSelectedTrackRecording() && !isSelectedTrackPaused()) {
StatsUtils.setLocationValues(activity, location, true); lastLocation = location;
} else { StatsUtils.setLocationValues(getActivity(), location, true);
if (lastLocation != null) { } else {
lastLocation = null; if (lastLocation != null) {
StatsUtils.setLocationValues(activity, lastLocation, true); lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
}
} }
} }
} }
@@ -175,12 +173,13 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onTrackUpdated(final Track track) { public void onTrackUpdated(final Track track) {
if (isResumed()) { if (isResumed()) {
final FragmentActivity activity = getActivity(); getActivity().runOnUiThread(new Runnable() {
activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
lastTripStatistics = track != null ? track.getTripStatistics() : null; if (isResumed()) {
updateUi(activity); lastTripStatistics = track != null ? track.getTripStatistics() : null;
updateUi(getActivity());
}
} }
}); });
} }
@@ -229,11 +228,12 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public boolean onMetricUnitsChanged(final boolean metric) { public boolean onMetricUnitsChanged(final boolean metric) {
if (isResumed()) { if (isResumed()) {
final FragmentActivity activity = getActivity(); getActivity().runOnUiThread(new Runnable() {
activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateUi(activity); if (isResumed()) {
updateUi(getActivity());
}
} }
}); });
} }
@@ -243,11 +243,12 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public boolean onReportSpeedChanged(final boolean speed) { public boolean onReportSpeedChanged(final boolean speed) {
if (isResumed()) { if (isResumed()) {
final FragmentActivity activity = getActivity(); getActivity().runOnUiThread(new Runnable() {
activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateUi(activity); if (isResumed()) {
updateUi(getActivity());
}
} }
}); });
} }