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.)
Related
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 have an activity that loads content from the internet when it initially loads, however the order it takes is:
1) User hits button to go to new activity
2) App stays on old activity
3) App loads content from internet (usually takes about a second or two)
4) App brings user to new activity with content already loaded
Now this is fine, however it can be confusing for a user because while they are still on the original activity, there is no indication that their input did anything. If the user were to click the button again, it wouldn't register that as another click on the original activity, it would register that as a click on the new activity which is still loading, which may cause a user to end up somewhere they did not wish to be.
I'd like to be able to fix this by having the order of the process be:
1) User hits button to go to new activity
2) Old activity disappears, brings user to "blank" new activity without content loaded
3) Display a loading wheel
4) App loads content from internet
5) Content is displayed and loading wheel disappears.
However I can't figure out how to accomplish this, I placed all my code in the onResume() method because I thought that would work, but the content loaded the same way as it always has, does anyone have any suggestions on how to accomplish what I want? Here is the code in my onResume() method:
protected void onResume() {
super.onResume();
setContentView(R.layout.coupon);
//method call to access the URL needed to display the content
accessURL(Global.contentURL);
}
Any help would be greatly appreciated.
You can use an AsyncTask that creates a ProgressDialog while it fetches the data in the background. There are many questions about this on SO (e.g. How to use AsyncTask to show a ProgressDialog while doing background work in Android?) as well as on the Internet.
I am making an android app. I have a main activity and i want to show distance and speed on main activity. But there is a button View Map on main activity as well. If user clicks it then he/she should see his/her travelled track on map. User should stop his/run from main activity means that user should be able to go back to main activity and then stop. How can i create map activity which runs in background and show distance and speed in main activity. Thanks in advance.
You should probably not think about having an Activity run in the background and instead have some other object that manages all the location information. Most of the time, you only have one Activity on screen and when its not on screen, it is paused and not working.
I would try to have an class that extends LocationListener, manage location information in that object, then whenever it is needed, plug the information into an appropriate View that is shown when the user presses "View Map" button you have.
You should take a look at the Google MyTracks app, it does exactly what you want and it is open source.
http://code.google.com/p/mytracks/
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
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!