Skip to content

Commit 1e67166

Browse files
committed
Improved lightweight mode transitions. Now peer images are generated in the background as the state of the map changes, rather than waiting until deinitialization. This yields much better usability, and fewer flashes and quirks.
1 parent 6d9daa1 commit 1e67166

File tree

1 file changed

+198
-43
lines changed

1 file changed

+198
-43
lines changed

GoogleMaps/native/android/com/codename1/googlemaps/InternalNativeMapsImpl.java

Lines changed: 198 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
import com.google.android.gms.maps.MapView;
2121
import com.google.android.gms.maps.GoogleMap;
2222
import com.codename1.impl.android.AndroidNativeUtil;
23+
24+
import java.util.ArrayList;
2325
import java.util.HashMap;
26+
import java.util.Timer;
27+
import java.util.TimerTask;
2428

2529
import com.google.android.gms.maps.OnMapReadyCallback;
2630
import com.google.android.gms.maps.model.Marker;
@@ -77,58 +81,159 @@ public void run() {
7781
android.util.Log.d("CN1 Mapss", "Did not initialize maps because activity was null");
7882
}
7983
AndroidNativeUtil.registerViewRenderer(MapView.class, new AndroidNativeUtil.BitmapViewRenderer() {
80-
private boolean rendering;
81-
public Bitmap renderViewOnBitmap(View v, int w, int h) {
82-
if (rendering) {
84+
85+
public Bitmap renderViewOnBitmap(View v, final int w, final int h) {
86+
87+
PeerImage pi = PeerImage.getPeerImage(v);
88+
if (pi == null) {
89+
PeerImage.submitUpdate(v, w, h);
8390
return null;
8491
}
85-
rendering = true;
86-
try {
87-
// prevent potential exception during transitions
88-
if(w < 10 || h < 10) {
89-
rendering = false;
90-
return null;
91-
}
92-
final MapView mv = (MapView)v;
93-
if(mv.getParent() == null || mv.getHeight() < 10 || mv.getWidth() < 10) {
94-
return null;
95-
}
96-
final Bitmap[] finished = new Bitmap[1];
97-
AndroidNativeUtil.getActivity().runOnUiThread(new Runnable() {
98-
99-
public void run() {
100-
mv.getMap().snapshot(new GoogleMap.SnapshotReadyCallback() {
101-
public void onSnapshotReady(Bitmap snapshot) {
102-
103-
synchronized(finished) {
104-
finished[0] = snapshot;//bmOverlay;
105-
finished.notify();
106-
}
107-
}
108-
});
109-
}
92+
if (pi.peerImage == null || pi.peerW != w || pi.peerH != h) {
93+
PeerImage.submitUpdate(v, w, h);
94+
return null;
95+
}
96+
pi.lastUsed = System.currentTimeMillis();
97+
return pi.peerImage;
11098

111-
});
99+
}
100+
});
101+
}
112102

113-
com.codename1.ui.Display.getInstance().invokeAndBlock(new Runnable() {
114-
@Override
115-
public void run() {
116-
synchronized(finished) {
117-
while(finished[0] == null) {
118-
try {
119-
finished.wait(100);
120-
} catch(InterruptedException er) {}
121-
}
122-
}
103+
private static class PeerImage {
104+
105+
Bitmap peerImage;
106+
int peerW;
107+
int peerH;
108+
Timer timer;
109+
long lastUsed;
110+
111+
112+
PeerImage() {
113+
lastUsed = System.currentTimeMillis();
114+
}
115+
116+
public static PeerImage getPeerImage(View v) {
117+
return peerImages.get(v);
118+
}
119+
120+
public void update(View v, final int w, final int h) {
121+
// prevent potential exception during transitions
122+
if(w < 10 || h < 10) {
123+
124+
return;
125+
}
126+
final MapView mv = (MapView)v;
127+
if(mv.getParent() == null || mv.getHeight() < 10 || mv.getWidth() < 10) {
128+
return;
129+
}
130+
AndroidNativeUtil.getActivity().runOnUiThread(new Runnable() {
131+
132+
public void run() {
133+
mv.getMap().snapshot(new GoogleMap.SnapshotReadyCallback() {
134+
public void onSnapshotReady(Bitmap snapshot) {
135+
peerImage = snapshot;
136+
peerW = w;
137+
peerH = h;
138+
lastUsed = System.currentTimeMillis();
123139
}
124140
});
125-
return finished[0];
126-
} finally {
127-
rendering = false;
141+
}
142+
143+
});
144+
145+
}
146+
147+
148+
149+
150+
private static PendingUpdate findPendingUpdate(View v) {
151+
synchronized(pendingUpdates) {
152+
for (PendingUpdate u : pendingUpdates) {
153+
if (u.view == v) {
154+
return u;
155+
}
128156
}
129157
}
130-
});
158+
return null;
159+
}
160+
161+
private static void submitUpdate(View v, int w, int h) {
162+
synchronized(pendingUpdates) {
163+
PendingUpdate existing = findPendingUpdate(v);
164+
if (existing == null) {
165+
existing = new PendingUpdate();
166+
existing.view = v;
167+
existing.w = w;
168+
existing.h = h;
169+
pendingUpdates.add(existing);
170+
existing.schedule();
171+
}
172+
existing.w = w;
173+
existing.h = h;
174+
}
175+
176+
}
177+
178+
private static void clearOldest() {
179+
synchronized (peerImages) {
180+
int maxNum = 5;
181+
long currMark = System.currentTimeMillis();
182+
ArrayList<PeerImage> toRemove = new ArrayList<PeerImage>();
183+
while (peerImages.size() > 5) {
184+
View oldest = null;
185+
PeerImage oldestImg = null;
186+
for (View vimg : peerImages.keySet()) {
187+
PeerImage img = peerImages.get(vimg);
188+
if (oldest == null || img.lastUsed < oldestImg.lastUsed) {
189+
oldest = vimg;
190+
oldestImg = img;
191+
}
192+
}
193+
if (oldest != null) {
194+
peerImages.remove(oldest);
195+
}
196+
197+
}
198+
199+
}
200+
}
201+
131202
}
203+
204+
static HashMap<View, PeerImage> peerImages = new HashMap<View,PeerImage>();
205+
private static class PendingUpdate {
206+
private View view;
207+
private int w;
208+
private int h;
209+
long requestTime;
210+
Timer timer;
211+
212+
213+
214+
private void schedule() {
215+
timer = new Timer();
216+
TimerTask tt = new TimerTask() {
217+
@Override
218+
public void run() {
219+
synchronized(pendingUpdates) {
220+
pendingUpdates.remove(PendingUpdate.this);
221+
}
222+
PeerImage pe = peerImages.get(view);
223+
if (pe == null) {
224+
pe = new PeerImage();
225+
peerImages.put(view, pe);
226+
}
227+
pe.update(view, w, h);
228+
229+
}
230+
};
231+
timer.schedule(tt, 1000L);
232+
}
233+
}
234+
static java.util.ArrayList<PendingUpdate> pendingUpdates = new java.util.ArrayList<PendingUpdate>();
235+
236+
132237
private static boolean initialized = false;
133238
private static void initMaps() {
134239
if (!initialized) {
@@ -172,8 +277,10 @@ public void run() {
172277
listeners.put(m, key);
173278
}
174279
markerLookup.put(key, m);
280+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
175281
}
176282
});
283+
177284
return key;
178285
}
179286

@@ -186,6 +293,7 @@ public void setPosition(final double lat, final double lon) {
186293
AndroidNativeUtil.getActivity().runOnUiThread(new Runnable() {
187294
public void run() {
188295
mapInstance.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(lat, lon)));
296+
PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
189297
}
190298
});
191299
}
@@ -195,6 +303,7 @@ public float getZoom() {
195303
AndroidImplementation.runOnUiThreadAndBlock(new Runnable() {
196304
public void run() {
197305
result[0] = mapInstance.getCameraPosition().zoom;
306+
198307
}
199308
});
200309
return result[0];
@@ -204,6 +313,7 @@ public void setZoom(final double lat, final double lon, final float zoom) {
204313
AndroidNativeUtil.getActivity().runOnUiThread(new Runnable() {
205314
public void run() {
206315
mapInstance.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), zoom));
316+
PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
207317
}
208318
});
209319
}
@@ -218,6 +328,8 @@ public void run() {
218328
mapInstance.clear();
219329
markerLookup.clear();
220330
listeners.clear();
331+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
332+
221333
}
222334
});
223335
}
@@ -248,6 +360,7 @@ public void run() {
248360
p.remove();
249361
paths.remove(param);
250362
}
363+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
251364
}
252365
});
253366
}
@@ -284,6 +397,7 @@ public void run() {
284397
return;
285398
}
286399
mapInstance.setMapType(GoogleMap.MAP_TYPE_NORMAL);
400+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
287401
}
288402
});
289403
}
@@ -304,6 +418,7 @@ public void setShowMyLocation(boolean show) {
304418
@Override
305419
public void run() {
306420
mapInstance.setMyLocationEnabled(showMyLocation);
421+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
307422
}
308423
});
309424
}
@@ -337,6 +452,7 @@ public boolean onMarkerClick(Marker marker) {
337452
mapInstance.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
338453
public void onCameraChange(CameraPosition position) {
339454
MapContainer.fireMapChangeEvent(InternalNativeMapsImpl.this.mapId, (int) position.zoom, position.target.latitude, position.target.longitude);
455+
PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
340456
}
341457
});
342458
mapInstance.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@@ -382,6 +498,7 @@ public void run() {
382498
view = null;
383499
return;
384500
}
501+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
385502
}
386503
});
387504
return view;
@@ -415,6 +532,7 @@ public void setRotateGestureEnabled(boolean e) {
415532
@Override
416533
public void run() {
417534
mapInstance.getUiSettings().setRotateGesturesEnabled(rotateGestureEnabled);
535+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
418536
}
419537
});
420538
}
@@ -427,6 +545,7 @@ public long finishPath(long param) {
427545
@Override
428546
public void run() {
429547
paths.put(key, mapInstance.addPolyline(currentPath));
548+
//PeerImage.submitUpdate(view, view.getWidth(), view.getHeight());
430549
}
431550
});
432551
return key;
@@ -499,6 +618,7 @@ public void onPause() {
499618
try {
500619
if(view != null) {
501620
view.onPause();
621+
502622
}
503623
} catch (Exception ex) {
504624
ex.printStackTrace();
@@ -533,6 +653,24 @@ public void onLowMemory() {
533653
try {
534654
if(view != null) {
535655
view.onLowMemory();
656+
synchronized(pendingUpdates) {
657+
PendingUpdate toRemove = null;
658+
for (PendingUpdate u : pendingUpdates) {
659+
if (u.view == view) {
660+
if (u.timer != null) {
661+
u.timer.cancel();
662+
u.timer = null;
663+
}
664+
toRemove = u;
665+
}
666+
}
667+
if (toRemove != null) {
668+
pendingUpdates.remove(toRemove);
669+
}
670+
671+
672+
}
673+
peerImages.clear();
536674
}
537675
} catch (Exception e) {
538676
e.printStackTrace();
@@ -541,6 +679,23 @@ public void onLowMemory() {
541679

542680
public void deinitialize() {
543681
AndroidNativeUtil.removeLifecycleListener(this);
682+
synchronized(pendingUpdates) {
683+
PendingUpdate toRemove = null;
684+
for (PendingUpdate u : pendingUpdates) {
685+
if (u.view == view) {
686+
if (u.timer != null) {
687+
u.timer.cancel();
688+
u.timer = null;
689+
}
690+
toRemove = u;
691+
}
692+
}
693+
if (toRemove != null) {
694+
pendingUpdates.remove(toRemove);
695+
}
696+
697+
}
698+
PeerImage.clearOldest();
544699
}
545700

546701
public void initialize() {

0 commit comments

Comments
 (0)