Android GoogleMaps slow onMapClick response - android

I set a click listener (GoogleMap.OnMapClickListener) for GoogleMap object in the onMapReady() method like this.
#Override
public void onMapReady(GoogleMap map) {
addClickListener(map);
}
Here is the addClickListener():
private void addClickListener(GoogleMap map) {
map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng point) {
Log.d("ON_MAP_CLICK", "1. OnMapClick called");
handleOnMapClick(point);
}
});
}
Since I set the map ready in the onMapReady method it is logical that I also add the click listener there.
The problem is that the delay for clicking on the map and the code to register that click is around 1 second while is should be instant.
Problem: The problem is not the time it takes to call addClickListener(GoogleMap) but the time that onMapClick() registers a click on the map (around 1 second).
Why is it so slow?
I am using GoogleMap V2
Thanks!

It is obvious that addClickListener method is called after 1 second because onMapReady call back will called only after intializing the map. So it take some delay initially for calling your addClickListener method.
So you will observe this delay only for the first time not all the time and it is working as like it is expected, No changes required in your code

onMapReady will call after the map is initialized, i had a project that took a while to load the map making all the functions "slow".
You can try to load the map earlier to prevent that by adding this to the Splashscreen or Activity.
new Thread(new Runnable() {
#Override
public void run() {
try {
MapView mv = new MapView(getApplicationContext());
mv.onCreate(null);
mv.onPause();
mv.onDestroy();
}catch (Exception ignored){
}
}
}).start();

Related

How to call retrofit api call in sequence of 5sec after onCameraChange(CameraPosition arg0) event on map

I am working on google map with retrofit2 api call.
on every camera change i have to call api.
problem is when user swipe/pinch-zoom on map every time onCameraChange(CameraPosition arg0) method will fire and my api call also.
so multiple time api call are running and because of this my output on map is ruined completely.
#Override
public void onCameraChange(CameraPosition arg0) {
// TODO Auto-generated method stub
camerachange();
}
public void camerachange() {
Log.e("temp", "camera change");
// jarray = new JSONArray();
jarray = new ArrayList<String>();
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
jarray.add(String.valueOf(bounds.southwest.latitude));
jarray.add(String.valueOf(bounds.southwest.longitude));
jarray.add(String.valueOf(bounds.northeast.latitude));
jarray.add(String.valueOf(bounds.northeast.longitude));
getPropertyList(jarray, 1) // this function has my retrofit call.
}
guys please help me with this concern.
main concern is multiple time call should not be there it must take last swipe/pinch-zoom effect.
thanks
You can use the OnMapLoadedCallback. From the documentation:
public abstract void onMapLoaded ()
Called when the map has finished rendering. This will only be called once. You must request another callback if you want to be notified again.
So, you need to set an initial setOnMapLoadedCallback for your map for example on the onMapReady method:
public void onMapReady(GoogleMap map) {
map.setOnMapLoadedCallback(this);
}
And then reset a new setOnMapLoadedCallback every time the event is consumed:
public void onMapLoaded() {
//TODO: Do your stuff
map.setOnMapLoadedCallback(this);
}
Also, take into account hte disclaimer from the documentation:
This event will not fire if the map never loads due to connectivity issues, or if the map is continuously changing and never completes loading due to the user constantly interacting with the map.

How to pause at an Android lifecycle stage until callback is called?

I am trying to use Google Maps API in my Android app. I need to call getMapAsync() to retrieve the map object asynchronously and I need to get the GoogleMap object instance before my fragment calls onResume(), because otherwise the GoogleMap object will still be null and it will throw an exception.
Therefore, I want the Activity that holds the fragment to pause at onResume() until onMapReadyCallback is invoked, so that I am guaranteed that the GoogleMap object is created and I could proceed in the Activity lifecycle. However, if I use any locks or barrier synchronizers in the Activity's thread (main thread), the thread will block and will not receive any callbacks and thus will wait forever.
I tried to use an object to implement the onMapReadyCallback and put it in another thread, but according to the documentation, I must have the callback in the main thread.
So how can I make the main thread wait until the callback has arrived and prevent it from running down its lifecycle methods???
You have two methods to resolve your issue. One crappy, and one better.
The crappy way
If this can helps for tests purposes for instance, this can works.
Call the Handler#postDelayed method in your onResume() method when your map object is null. Here's an example.
#Override
public void onResume(){
super.onResume();
doMapStuff();
}
public void doMapStuff()
{
if (mMap == null) {
new Handler().postDelayed(new Runnable() {
public void run() {
doMapStuff();
}
}, 250);
return;
}
// do your stuff on the map here.
}
public void onMapReady(GoogleMap map) {
mMap = map;
doMapStuff();
}
As the handler is created on the UI thread, the delayed runnable will also be executed on the UI thread, so you will be able to make your map stuff.
BUT This is a crappy way to do this. It can works for tests, but avoid using this way!
The good way
If your map object is null when onResume() is called, that means the onMapReady callback will be called further.
If your map object is set when onResume() is called, that means the onMapReady callback was already called, so it will not be called again.
Basically, you need to "duplicate" your calls between onResume() and onMapReady() methods.
#Override
public void onResume(){
super.onResume();
doMapStuff();
}
public void doMapStuff()
{
if (mMap == null)
return;
// do your stuff on the map here.
}
public void onMapReady(GoogleMap map) {
mMap = map;
doMapStuff();
}
You can't pause or delay the activity lifecycle without causing problems, as you have seen.
If all the data you need is not available at the time of an activity lifecycle method, you can delay the visibility of the UI and postpone other work that needs to be done in the Activity. Show some sort of spinner or progress bar until all the data and connections are available, then update the views in response to everything becoming available.
Do a check to make sure that onMapReady has completed. Would this work for you:
MapFragment mMapFragment;
#Override
public View onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
public void onMapReady(GoogleMap map){
mMap = map;
}
then in onResume do a check:
#Override
public void onResume(){
super.onResume();
if(mMap == null){
mMapFragment.getMapAsync(this);
}
//rest of code
}

How to detect moveCamera is finished on the Google map service?

I want to take a snapshot when moveCamera is finished.
I used both onCamerachange() and onMapLoaded() functions to Googlemap object,
But this callback handler's timing is not fit on my intention.
I want to move camera to what I want, and when loading map is finished, want to take a screnshot.
Who do you guys know about how can I do?
Thank you.
====================================================
+MYSOLUTION
Actually, I want to implement tilesloaded() call back function that is supported on the google map API of the javascript.
But, as a result, there is no function which is completely accomplished that function.
OnMapLoaded() callback function is just invoked once when the map is loaded first.
OnCameraChanged() or OnCancallableCallback is invoked before all the tiles are loaded.
So I implemented like below source code
...
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 10), this);
...
#Override
public void onFinish() {
mapFragment.getMapAsync(this);
}
..
#Override
public void onMapReady(GoogleMap googleMap) {
// TODO Auto-generated method stub
mMap = googleMap;// Add a marker in Sydney and move the camera
mMap.setOnMapLoadedCallback(this);
}
Now, when the camera is moved, onMapLoaded() is always invoked.
Thank you everybody.
You can implement this:
mMap.animateCamera(CameraUpdateFactory.zoomTo(16), 3000, new GoogleMap.CancelableCallback() {
#Override
public void onFinish() {
//Here you can take the snapshot or whatever you want
}
#Override
public void onCancel() {
}
});
The most detailed form of this method, GoogleMap.animateCamera(cameraUpdate, duration, callback), offers three arguments:
cameraUpdate
The CameraUpdate describing where to move the camera.
callback
An object that implements GoogleMap.CancellableCallback. This generalized interface for handling tasks defines two methods onCancel() and onFinished(). For animation, the methods are called in the following circumstances:
onFinish()
Invoked if the animation goes to completion without interruption.
onCancel()
Invoked if the animation is interrupted by calling stopAnimation() or starting a new camera movement.
Alternatively, this can also occur if you call GoogleMap.stopAnimation().
Source: Google Maps Android API Guides
So you are definitely in the right area by using the onCameraChange() and onMapLoaded() callback. The best way to handle this would be to handle your screenshot in the onMapLoaded() function.
Also, remember to use the newest libraries, and the support libraries when instantiating your map fragment. This is very important.
So:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...All of the other important things you have here
//Instantiate the map object using the support library
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
map.getMapAsync(this);
//Add the callback to your map object
map.setOnMapLoadedCallback(this);
}
#Override
public void onMapLoaded(){
//Perform screenshot here
}
EDIT
Here is code for a handler, complete with comments.
#Override
public void onCameraChange(){
//Constant for our time. I would put this below your class declaration
private static final int DELAY_TIME_IN_MILLI = 3000;
//Here is the handler for waiting
mMap.postDelayed(new Runnable() {
//This function runs after the time allotted below
#Override
public void run() {
//Call your screenshot function here
takeScreenShot();
}
},DELAY_TIME_IN_MILLI); //Our delay
}

Android maps v2 becomes low quality when map area is automatically moved

I am simulating a car moving on a pre-recorded path on Android maps v2. When I zoom on the path by hand, it works great, but when I move the camera over the path with mMap.animateCamera(), it doesn't load the visible map area, I only get a very pixelated, low quality map. If I touch the screen and move the map or zoom a little, then it loads again this part.
How can I achieve, that it always loads clearly the visible part?
EDIT:
I added an example image: this is what I see when I don't touch the map. After I touch it, it becomes clear (similar to the bottom left part).
EDIT2:
I have an idea, that this is because Google want's to prevent the map to be cached by quickly moving the camera over an area. Is it possible, that this is the cause of this issue? (The map is showing Budapest, Hungary, which part of the map you can not download for offline use...) But here I only want to show the animation and place markers, I only need the visible area to be cached - are there any way to workaround this behaviour?
EDIT3:
The animation code:
new Thread(new Runnable() {
#Override
public void run() {
// ... Calculating and sending new location, in an infinite loop with sleeps for timing
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
}
});
}
}).start();
Finally found a solution. I was able to recreate your problem using the code you provided. I replaced your code with the following and it worked for me.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// ... Calculating and sending new location, in an infinite loop with sleeps for timing
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
}
});
}
}, 0, 2000);
Just remove your code for sleeping and replace the last argument in scheduleAtFixedRate (the 2000) with whatever value you were using for sleeping.
I had the same issue. Since it did not happen when not animating the camera, it had to be something related to that.
Apperently the camera has to be able to finish its operation, before it will update the background/roads etc.
Since my app updates the position every second and the map needs about 2 seconds to complete I end up with pixelated roads and no surroundings at all.
The solution is to use one of overloads of animateCamera:
public final void animateCamera (CameraUpdate update, int durationMs,
GoogleMap.CancelableCallback callback)
Moves the map according to the update with an animation over a
specified duration, and calls an optional callback on completion. See
CameraUpdateFactory for a set of updates.
I used for my case a duration of 900msec, so the animation is done before it receives a new location.
To get the callback to work you need to implement GoogleMap.CancelableCallback to your class. This requires you to add two overrides:
#Override
public void onFinish() {
}
#Override
public void onCancel() {
}
They are not required to get the problem solved, altough you are free to add extra logic there.
The call to update the camera can look like this:
cameraPosition = new CameraPosition.Builder()
.target(current)
.zoom(zoomLevel)
.bearing(bearing)
.tilt(tilt)
.build();
CameraUpdate update = CameraUpdateFactory.newCameraPosition(cameraPosition);
map.animateCamera(update, 900, this);

Android : Make application wait till the current location is found

I'm trying to make my app wait till the current location is found. I've tried few different ways using Threads and all have failed really. I was using wait() and notify() but application just hung and never found the current location.
I amen't using google map api as it is not part of the application. Does anyone have any ideas how to do this or examples.
EDIT : The Thread I was using did not start till the user pressed a button then within onLocationChanged other data is processed e.g. adding the new location to ArrayList, Calculate the distance between the current and last Location as well as the Time taken to get to the new location
You could try starting an AsyncTask in onCreateto get the location. Your default onCreate layout could be a "loading" page, then when your AsyncTask completes successfully with the location it draws your "real" UI.
So if I understand what you want to do correctly, then I would avoid making another thread in onClick(). Instead, onClick() should just request a location, display a progress dialog, and return. Since the work you want to do happens after you receive the new location, I would start an AsyncTask there. Then you finally remove the dialog box (removing it returns control to the user) when the AsyncTask finishes.
Code usually helps, so, I would put this in onCreate() or wherever:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.refresh();
}
});
And put this in your LocationListener:
public void refresh() {
myLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
myDialog = new ProgressDialog(myContext);
myDialog.setIndeterminate(true);
myDialog.show();
}
#Override
public void onLocationChanged(Location location) {
// now do work with your location,
// which your probably want to do in a different thread
new MyAsyncTask().execute(new Location[] { location });
}
And then you need an AsyncTask, which may look like this:
class MyAsyncTask extends AsyncTask<Location, Void, Void> {
#Override
protected Void doInBackground(Location... location) {
// start doing your distance/directions/etc work here
return null;
}
#Override
protected void onPostExecute(Void v) {
// this gets called automatically when you're done,
// so release the dialog box
myDialog.dismiss();
myDialog = null;
}
}

Categories

Resources