Skip to content

Commit 0a106ad

Browse files
rohanjain1comann
authored andcommitted
Pokemon expiry timer implemented: HandlerThread with messages posted on it for next expiring pokemon. (#214)
1 parent 6d09165 commit 0a106ad

File tree

4 files changed

+163
-0
lines changed

4 files changed

+163
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.omkarmoghe.pokemap.controllers;
2+
3+
import android.os.Handler;
4+
import android.os.HandlerThread;
5+
import android.support.design.widget.TabLayout;
6+
import android.util.Log;
7+
8+
import com.omkarmoghe.pokemap.models.events.MarkerUpdateEvent;
9+
10+
import org.greenrobot.eventbus.EventBus;
11+
12+
/**
13+
* Created by Rohan on 26-07-2016.
14+
*/
15+
16+
17+
public class MarkerRefreshController {
18+
19+
final private String TAG = MarkerRefreshController.class.getName();
20+
21+
private HandlerThread mThread;
22+
private Handler mHandler;
23+
private static final int DEFAULT_UPDATE_INTERVAL = 10 * 1000;//10 seconds : heartbeat
24+
private long updateInterval = DEFAULT_UPDATE_INTERVAL;
25+
private MarkerUpdateEvent mEvent;
26+
private Runnable markerExpiryUpdate;
27+
28+
private static MarkerRefreshController mInstance;
29+
30+
private MarkerRefreshController() {
31+
if (mThread == null) {
32+
33+
mThread = new HandlerThread("MarkerRefreshThread");
34+
mThread.start();
35+
mHandler = new Handler(mThread.getLooper());
36+
mEvent = new MarkerUpdateEvent();
37+
markerExpiryUpdate = new Runnable() {
38+
@Override
39+
public void run()
40+
{
41+
/**
42+
* Talking to:
43+
* {@link com.omkarmoghe.pokemap.views.map.MapWrapperFragment,}
44+
*/
45+
EventBus.getDefault().post(new MarkerUpdateEvent());
46+
}
47+
};
48+
49+
} else {
50+
throw new RuntimeException("Invalid state of Marker Refresh Thread.");
51+
}
52+
53+
}
54+
55+
/*
56+
* Singleton getter
57+
*/
58+
public static MarkerRefreshController getInstance() {
59+
if (mInstance == null) {
60+
mInstance = new MarkerRefreshController();
61+
}
62+
return mInstance;
63+
}
64+
65+
66+
/**
67+
* Cleanup thread state.
68+
* Must ensure thread is properly quitting to allow safe reInit when needed
69+
*/
70+
public void clear() {
71+
if(mThread!=null) {
72+
try {
73+
mThread.join();
74+
mThread.quit(); //I don't need to process the scheduled messages in queue.
75+
76+
} catch (InterruptedException e) {
77+
Log.d(TAG, "Quitting too soon.. doing final cleanup");
78+
} finally {
79+
mThread = null;
80+
mInstance = null;
81+
}
82+
}
83+
}
84+
85+
/**
86+
* Combo call for starting, resetting, refreshing, scheduling next update
87+
* Must be called separately after [@link notifyTimeToExpiry]
88+
*/
89+
public void reset() {
90+
getInstance().mHandler.removeCallbacks(markerExpiryUpdate);
91+
getInstance().mHandler.postDelayed(markerExpiryUpdate, updateInterval);
92+
updateInterval = DEFAULT_UPDATE_INTERVAL;
93+
}
94+
95+
/**
96+
* Hook to determine next closest expiration time.
97+
* Can be scheduled at regular intervals to use as a heartbeat.
98+
*
99+
* @param timeToExpiry
100+
*/
101+
public void notifyTimeToExpiry(long timeToExpiry) {
102+
if (updateInterval > timeToExpiry) {
103+
updateInterval = timeToExpiry;
104+
}
105+
}
106+
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.omkarmoghe.pokemap.models.events;
2+
3+
/**
4+
* Created by Rohan on 26-07-2016.
5+
*/
6+
7+
/**
8+
* Empty event.
9+
*/
10+
public class MarkerUpdateEvent {
11+
//int _Data = 404;
12+
}

app/src/main/java/com/omkarmoghe/pokemap/views/MainActivity.java

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import android.view.MenuItem;
1515
import com.google.android.gms.maps.model.LatLng;
1616
import com.omkarmoghe.pokemap.R;
17+
import com.omkarmoghe.pokemap.controllers.MarkerRefreshController;
1718
import com.omkarmoghe.pokemap.controllers.service.PokemonNotificationService;
1819
import com.omkarmoghe.pokemap.models.events.ClearMapEvent;
1920
import com.omkarmoghe.pokemap.models.events.InternalExceptionEvent;

app/src/main/java/com/omkarmoghe/pokemap/views/map/MapWrapperFragment.java

+43
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@
3131
import com.google.android.gms.maps.model.Marker;
3232
import com.google.android.gms.maps.model.MarkerOptions;
3333
import com.omkarmoghe.pokemap.R;
34+
import com.omkarmoghe.pokemap.controllers.MarkerRefreshController;
3435
import com.omkarmoghe.pokemap.controllers.app_preferences.PokemapAppPreferences;
3536
import com.omkarmoghe.pokemap.controllers.app_preferences.PokemapSharedPreferences;
3637
import com.omkarmoghe.pokemap.controllers.map.LocationManager;
3738
import com.omkarmoghe.pokemap.helpers.RemoteImageLoader;
3839
import com.omkarmoghe.pokemap.models.events.CatchablePokemonEvent;
3940
import com.omkarmoghe.pokemap.models.events.ClearMapEvent;
4041
import com.omkarmoghe.pokemap.models.events.GymsEvent;
42+
import com.omkarmoghe.pokemap.models.events.MarkerUpdateEvent;
4143
import com.omkarmoghe.pokemap.models.events.PokestopsEvent;
4244
import com.omkarmoghe.pokemap.models.events.SearchInPosition;
4345
import com.omkarmoghe.pokemap.models.map.GymMarkerExtended;
@@ -352,6 +354,7 @@ public void onFetch(Bitmap bitmap) {
352354
userSelectedPositionCircles.clear();
353355
}
354356
}
357+
MarkerRefreshController.getInstance().reset();
355358
}
356359

357360
private float getDistanceInMeters(double lat1, double lon1, double lat2, double lon2) {
@@ -527,6 +530,33 @@ public void onFetch(Bitmap bitmap) {
527530
}
528531
}
529532

533+
private void removeExpiredMarkers() {
534+
535+
if (mGoogleMap != null) {
536+
if (markerList != null && !markerList.isEmpty()) {
537+
for (Iterator<Map.Entry<String, PokemonMarkerExtended>> pokemonIterator = markerList.entrySet().iterator(); pokemonIterator.hasNext(); ) {
538+
Map.Entry<String, PokemonMarkerExtended> pokemonEntry = pokemonIterator.next();
539+
CatchablePokemon catchablePokemon = pokemonEntry.getValue().getCatchablePokemon();
540+
Marker marker = pokemonEntry.getValue().getMarker();
541+
542+
long millisLeft = catchablePokemon.getExpirationTimestampMs() - System.currentTimeMillis();
543+
if (millisLeft < 0) {
544+
marker.remove();
545+
pokemonIterator.remove();
546+
} else {
547+
marker.setSnippet(getExpirationBreakdown(millisLeft));
548+
if (marker.isInfoWindowShown()) {
549+
marker.showInfoWindow();
550+
}
551+
MarkerRefreshController.getInstance().notifyTimeToExpiry(millisLeft);}
552+
}
553+
MarkerRefreshController.getInstance().reset();
554+
}
555+
}
556+
557+
}
558+
559+
530560
private void showMapNotInitializedError() {
531561
if(getView() != null){
532562
Snackbar.make(getView(), getString(R.string.toast_map_not_initialized), Snackbar.LENGTH_SHORT).show();
@@ -593,6 +623,19 @@ public void onEvent(GymsEvent event) {
593623
setGymsMarkers(event);
594624
}
595625

626+
/**
627+
* Called whenever a MarkerUpdateEvent is posted to the bus. Posted by {@link MarkerRefreshController} when
628+
* expired markers need to be removed.
629+
*
630+
* @param event
631+
*/
632+
633+
@Subscribe(threadMode = ThreadMode.MAIN)
634+
public void onEvent(MarkerUpdateEvent event){
635+
removeExpiredMarkers();
636+
}
637+
638+
596639
private void clearCatchedPokemonCircle() {
597640

598641
//Check and eventually remove old marker

0 commit comments

Comments
 (0)