I have an android application that uses Google Maps. My first activity starts a mapview with some clickable icons. When an icon is clicked, a new activity (intent) is started with a different map. From the new map I then click the back button which takes me back to my first map. However, when I start zooming or moving around in the map, only the tiles that originally loaded will show up. How can I change this?
If you change the phone orientation the map will refresh and then it behaves normally (becuase the app restarted) so I added android:configChanges="orientation" to stop the restarting on orientation change. I added that because I don't want to reload all the markers again (uses a web service and can take some time).
I just want the tiles to load when I click "back" to the original map. Any ideas?
I ran into this problem recently as well! Check your log - you're probably getting an error along the lines of "IllegalStateException: Connection pool shut down." Also like me, the only answers you found seemed to be for people who hadn't set up their Google API key right. :-\
I eventually ran into this link. (You usually need to be signed in to your Google account to read these posts)
It appears as though there's a bug that only allows one map activity per application. Something to do with the map refreshing, I guess. I got around it by finishing each map activity after loading the new one, causing the activity to be reloaded in its entirety when the user returns to it. It's not ideal, but it's worked well for me so far.
In some more detail:
Save any information about the map you want to retrieve later. Map center and map zoom first come to mind. Put it somewhere global, or pass it in with your intent.
After launching the intent for the second activity, call finish() on the first one. If you want the two maps to appear to the user as the same map, then you'll want to kill the sliding transition that occurs by default when a new activity is started. Do that by calling this line immediately after finish():
overridePendingTransition(0, 0);
When your second map activity needs to finish, repeat step 1 if needed and then load the first map activity back using the same method as step 2. The code from 2 would go in the onBackPressed() method of the activity, and wherever else its appropriate (maybe you have a cancel button or something).
In the onCreate of the first activity, make sure you check for stuff that's been saved from the last time that activity was being viewed and modify your map appropriately.
Maybe that was verbose, but I use this site a lot and I always appreciate the answers that say too much a lot more than the ones that say too little, haha!
Related
I have noticed a few posters on Stack Overflow attempting this, but my situation is a little different. I have a Login class and when the user authenticates, I take declare an Intent to them to my NavDrawer class, which serves as the Main Activity. I am using a Map Fragment to show a Google Map, but when the user logs in for the very first time, the blue dot ( call to setMyLocationEnabled = true) is not visible. This is due to the Map loading in the background before the location permission request is loaded. Of course, after you grant permission and restart the app manually, the blue dot is visible as permission is already granted.
I am trying to build my logic so that as soon as the user logs in, they must grant permission before the map will load. That way, the blue dot will be enabled.
Apparently this is a known bug: https://issuetracker.google.com/issues/73122459
And one suggestion in the link above is to request permission in Activity before calling setContentView. I attempted to do this, but my Map is still loading in the background. Since location is integral to the app, I was thinking I could throw up a screen that prevents the map from being shown, that takes them to their settings. Then when they return, the map will be visible.
I like how LimeBike does it, with a transparent map behind it, so you still see what should be there. Once you navigate to your settings and enable location and return, their map loads and the blue dot pops up. Does anyone have experience implementing something similar?
If showing blue dot is so essencial on first launch before permissions granted - why not trying to request permission on preivious screen. Right on Login screen. And to not disturb users too early - do it after user successfully logins.
i.e.
1. User logs in
2. User stays on Login screen, sees popup with permission
3. Accepts or declines - either way navigates to Map screen
put that permissionns code into the onstart , only after permission success call on createview.
If your app flow allows you to request the location permission before showing the MapView, that's the simplest solution. You might also potentially be able to use a static map image in the background on your first launch, and then switch over to the screen with the real map after the permission request, depending on what you need to show there.
Alternatively, if you want or have to have the MapView visible behind the permission-request dialog, I've found that you can take one of two approaches to restart the MapView, whereupon it will properly get location updates in the "My Location" layer (the blue dot). You do this from onRequestPermissionsResult, if permission has been granted.
1. Replace the MapView
I placed the MapView, by itself, in a FrameLayout. First save the state of the existing MapView and shut it down:
val oldMapState = Bundle()
with(mapView) {
onSaveInstanceState(oldMapState)
onPause()
onStop()
onDestroy()
}
Then create a new MapView, run it up through to "resumed" state, and swap it in to the FrameLayout, in place of the old map view:
val mapContainer = branchMapView.parent as FrameLayout
val newBranchMapView = MapView(mapContainer.context).apply {
onCreate(oldMapState)
getMapAsync { it.isMyLocationEnabled = true }
onStart()
onResume()
}
There will be a flash of background while the new MapView loads, but I haven't found it too bothersome. One could probably refine this further to hide the new MapView for a couple of seconds, while it loads, but I don't know of a way to monitor the loading progress, so it would never be perfect; and you would run the risk of the interrupting the user manipulating the old map before you cut over.
2. Restart the MapView
The second approach is similar, but instead of creating a new MapView, we just restart the same one. As far as I can tell, calling onCreate again, after onDestroy seems to have no ill effects, except that the background goes solid black for a moment, for some reason, which I find doesn't look as good. It also wouldn't allow you to do any overlapped loading of the new map, if you wanted to try to minimize the visual disruption. However, from a code perspective, it seems like a slightly simpler solution.
If you are using a MapFragment, perhaps you can do something similar, removing the old fragment and adding a new one dynamically. (Not sure if re-use is possible; I have only tested with a MapView.)
In Android, startActivityForResult() and onActivityResult() can be used to pass a bundle from an activity to its PARENT_ACTIVITY (ref this question, for instance, or this question). This requires overriding onBackPressed() to call finish() instead.
The semantics of this feel "wrong" to me in a case where pressing back isn't about finishing some step in a flow and returning a value. In my case, when the user presses back, they're effectively saying "I changed my mind and want to go back to the previous screen" not "I'm done with the current screen and want to go forward," which is how finish() feels to me.
Is there another alternative where I just want the activity I'm going back to to know some info about state of the current activity? Or is the consensus in the community that startActivityForResult is the right way to go, regardless of the semantics/intent?
Details follow:
I am working on an app including two activities centered around Google Maps for Android, SelectActivity and EditActivity. SelectActivity shows multiple points of interst on the map and allows the user to select an existing POI or create a new POI. EditActivity allows the user to edit details.
EditActivity is defined in the manifest with SelectActivity as its PARENT_ACTIVITY, so pressing the back button in EditActivity returns to SelectActivity. There are some other activities that allow the user to drill down deeper, after EditActivity, but they are not relevant to this question.
When SelectActivity launches EditActivity, it includes a bundle with the current map parameters in the Intent, so EditActivity starts with the same map view as SelectActivity.
Right now, SelectActivity sets the map to an area around the device's current location from Location Services. This is the desired behavior in most cases because the user will usually want to be editing things around their immediate location.
However, sometimes users need to edit multiple things somewhere else on earth. Ideally, when SelectActivity is resumed by returning from EditActivity, a bundle containing the current map parameters (center, zoom level, etc) would be created and passed, and then SelectActivity would use the map parameters from that bundle instead of the default device-centered behavior.
I need to open two activities simultaneously, one of them is an Android intent for launching route on Google maps.
For this I used, PendingIntent.getActivities. Using this method it looks whenever I launch more than one activity the data doesn't gets delivered to Android map activity.
As a workaround for this I created another Activity and from there I am launching these two activities, using startActivity twice.
This starts both of them, but not in the same required sequence, the map activity is always on top, while the second one comes to front when I press the back and finish the Map, even using delayed launch of the other activity does not creates any effect.
Any help ?
So,
Finally I used a work around, and launched the activity using pending intent, and it's working now.
I have an activity, DogActivity, with a slider. When the user slides view PawsView to a certain degree, I start another activity, CatActivity, using startActivity(intent). If the user clicks the back button, normally the user returns to DogActivity. Here is my problem: if in Developer options I set Do not keep activities then when the user clicks the back button and thus returns to DogActivity, the slider is not asserted and so PawsView is back to its original position; however, if I don't have that option selected, upon returning to DogActivity the slider is still asserted (the sliding already occurred).
Since I don't want to depend on the user selecting or deselecting Do not keep activities, I need to do this programmatically. So does anyone know how to do this? I have tried putting the appropriate code inside onResume but that has no effect. It's as if finishing CatActivity has no effect on DogActivity. BTW, the view I am using to display PawsView is a custom view.
I already tried using a handler with postDelayed to pull PawsView back to normal, but the handler always executes before the startActivity is executed. If on the other hand I start a proper Thread to run the call to close the slider, I get an error about the wrong thread trying to change the layout.
Another way of asking the question may be: How do I force onResume to be called even when Do not keep activities is NOT selected on a user's device.
You could try to launch CatActivity using startActivityForResult and then handle the result in onActivityResult and do the necessary setup from there. It's sort of like forcing onResume.
I have it so that when the user pushes the back button it leaves the activity and goes back to the main part of the application. The problem is that I am using a map and when it goes back the GPS is still tracking. How would I get it so that when they leave the map activity the GPS stops tracking?
If you're using a MyLocationOverlay on the map, be sure to call disableMyLocation() in your activity's onPause (and enable it with enableMyLocation() in onResume). See the docs on MyLocationOverlay.
I have no experience with location services API, but are you finish()'ing the map activity in your back button code? If yes, you could stop tracking in onDestroy(), otherwise just before calling the main activity.
Also, if you don't ever want the activities between the main one and the map activity to be remembered in the task stack (that is, you pass through them only "forward"), consider using android:noHistory="true" in your manifest for them. This way you can avoid overriding back button.
Also see here: android how to stop gps
pressing back button brings user to previous entry in activity stack, and
activity he just left receives onPause() callback - this is the best (and only)
place to stop everything your activity was doing