How can I check wether a (Google maps API) map has loaded? - java

I have started building an android application that focuses on a map from google-play-services-libs. When I start the app, it takes a while for the map to load from the gray grid to showing the map image.
I'd like to move/play around a bit with the map when it has fully loaded the part that is currently on screen. I have however been unable to find a way to programmatically check whether the map has loaded.
How can I achieve this?
In short:
From a instance of GoogleMap, how do I determine if it is actually showing something?

You can try using a OnCameraChangeListener on your map. The onCameraChange call will be called when the map's tiles are initially loaded.
this.map.setOnCameraChangeListener(new OnCameraChangeListener() {
public void onCameraChange(CameraPosition arg0) {
isMapReady = true;
map.setOnCameraChangeListener(null);
}
});

chckReady() function checks whether the map is ready or not
public class MapView extends android.support.v4.app.FragmentActivity {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ui_settings_demo);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
}
}
private boolean checkReady() {
if (mMap == null) {
return false;
}
}
}

Related

Here SDK - Change map location

This is the sample code from Here API. But the problem I have is that the initial location where the map is loaded is wrong. What I need is for the map to be displayed where you are.
What is the method that modifies the position of the map?
private MapViewLite mapView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get a MapViewLite instance from the layout.
mapView = findViewById(R.id.map_view);
mapView.onCreate(savedInstanceState);
}
private void loadMapScene() {
// Load a scene from the SDK to render the map with a map style.
mapView.getMapScene().loadScene(MapStyle.NORMAL_DAY, new MapScene.LoadSceneCallback() {
#Override
public void onLoadScene(#Nullable MapScene.ErrorCode errorCode) {
if (errorCode == null) {
mapView.getCamera().setTarget(new GeoCoordinates(52.530932, 13.384915));
mapView.getCamera().setZoomLevel(14);
} else {
Log.d(TAG, "onLoadScene failed: " + errorCode.toString());
}
}
});
}
This is the piece of code that hard codes the position:
mapView.getCamera().setTarget(new GeoCoordinates(52.530932, 13.384915))
Instead, set the coordinates to be the user's click. In order to do so, you will need to surround that piece of code with an onTouch() listener and check the action of the user. I'll use an ImageView as an example. So something like this:
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
//whatever you want to do
//to fetch the coordinates of the user's click use event.getX() and event.getY()
}
return true;
}
});

How to create proper "this" object as argument? [duplicate]

This question already has answers here:
What is the meaning of "this" in Java?
(22 answers)
Closed 4 years ago.
I'm trying to write a function where I have to pass an Activity object to a method that requires such an argument. Usually in such case I'm supposed to just type "this" and it automatically recognizes which type of object it's supposed to create. But sometimes this doesn't work and it for whatever reason reassings a different type of object than the one that is required. For example, I actually use the exact same method in both of these cases:
if (checkLocationPermission(this)){
In this first one, the program automatically recognizes "this" as an Activity object. Here's the second one:
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(this)){
In this case the exact same method recognizes "this" as an OnSuccessListener instead of an Activity.
Another example I have in the same program is one where "this" object is supposed to be a Looper but instead it again gets recognized as an OnSuccessListener:
fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),this);
I don't know how to actually select the proper type of object for "this" argument since I can only type the same damn word.
EDIT:
Here's the full code. I used Looper.this just so you can find it easier. I also tried with MapsActivity.this and it doesn't work:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap;
private GoogleApiClient googleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
private FusedLocationProviderClient fusedLocationClient;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; //Request code to send to Google Play Services
private LocationRequest locationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
locationRequest = LocationRequest.create().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(10*1000).setFastestInterval(1*1000);
}
private void setUpMapIfNeeded(){
if (mMap==null){
SupportMapFragment mapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
//setUpMap();
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG,"Location Services Connected");
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (checkLocationPermission(this)){
fusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(MapsActivity.this)){
fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),Looper.this);
}
else{
handleNewLocation(location);
}
}
});
}
}
public static boolean checkLocationPermission(Activity activity){
if(ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION},0);
return false;
}
return true;
}
private void handleNewLocation(Location location){
Log.d(TAG,location.toString());
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG,"Location Services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()){
//Starts an Activity that tries to resolve the error
try {
connectionResult.startResolutionForResult(this,CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
else{
Log.i(TAG,"Location services connection failed code: " + connectionResult.getErrorCode());
}
}
#Override
protected void onResume(){
super.onResume();
setUpMapIfNeeded();
googleApiClient.connect();
}
#Override
protected void onPause(){
super.onPause();
if (googleApiClient.isConnected()){
googleApiClient.disconnect();
}
}
#Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
}
this corresponds to the object in which it is used. onSuccess is a method of OnSuccessListener class and hence this refers to OnSuccessListener. You need to use ActivityName.this. For example if you activity name is MainActivity, then
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(MainActivity.this)){
When you use an anonymous inner class, such as a listener, and use this, it refers to the anonymous inner class, because that's your current location.
For instance, with an OnClickListener:
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//"this" here will refer to the OnClickListener instance you create
}
}
Nothing is being "created" with a this argument. It's a direct reference to the current enclosing class. If you need to reference the Activity, you can use:
ActivityClassName.this
as long as you're in an inner class and not a static class.
If you use a lambda (only available for API 24+):
view.setOnClickListener((v) -> {
//"this" will reference your Activity because there's no inner class anymore
}
the this refers to the object of the immediate enclosing class. So, if you have some interface or class as an argument to a function, we usually do like this :
functionThatTakesInterfaceOrClassAsArgument( new TheInterfaceOrClass {
#Override
public void someMethod () {
// if you use `this` here, it refers to the object of `TheInterfaceOrClass`
}
});
If you want to use the object corresponding to an enclosing class (yet not the immediate enclosing class) using <className>.this
So, if the name of the enclosing Activity is MyActivity, one would need to use MyActivity.this.

Cannot zoom above whole country, java Google Maps V2

I am developing a project with a map displaying 100 markers in a country (Greece). When my map is open while launching application in my mobile android phone, map zooms in Africa and in a tablet device it zooms in different location- country. This happens when my location is disabled through settings of my device. How can I set the map to zoom above whole country Greece when my map is loaded for first time? in any android device application is installed?
Please check my code below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
/**
* Check mMap. In case it is not null then setUpMap
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
When I activate current location then it zooms on level 14 over my location. I need to keep this functionality when location setting are enabled.
// Show the current location in Google Map
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
mMap.animateCamera(CameraUpdateFactory.zoomTo(14));
You can do:
map.moveCamera( CameraUpdateFactory.newLatLngZoom(new LatLng(xxxx,xxxx) , 14.0f) );
Where the coords, are for example the "middle" of Greece. And you will need to set some SharedPreference to know if is the first time that the app is open.
You can use the new version of API that calls you when the map is loaded:
http://developer.android.com/reference/com/google/android/gms/maps/GoogleMap.OnMapLoadedCallback.html
You can easily check if it is the first time by using a simple "singleton" or static variable.
About the Zoom, I would recomend you to build a LatLngBounds and zoom on it.
You can do this by iterating over all the Markers:
LatLngBounds.Builder zoomTo = LatLngBounds.builder();
for (Marker marker : markersList) {
zoomTo.include(marker.getPosition());
}
final LatLngBounds workArea = zoomTo.build();
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(workArea, 50));
mMap.setOnMapLoadedCallback(null);
}
});

Android - getting current location through Google Map

I am developing an app related to Google map. I have done following steps successfully.
Created API key to access Google Map
Added Google Play Services Library in my app
Added required permissions
Added map in my activity with SupportMapFragment
Added a separate class MyMap.java to manipulate the map
Passed tow parameters to this class - Context of main activity and object of GoogleMap
Turned Wi-Fi and GPS on and ran the app
After this I am getting map with nice look and controls.
MyMap.java
public class MyMap implements ConnectionCallbacks, OnConnectionFailedListener {
private Context context;
private GoogleMap map;
private GoogleApiClient client = null;
public MyMap(Context context, GoogleMap map) {
this.context = context;
this.map = map;
client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle arg0) {
Toast.makeText(context, "Connected", 1).show();
Location mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(client);
if (mLastLocation != null) {
Toast.makeText(
context,
String.valueOf(mLastLocation.getLatitude()) + ","
+ String.valueOf(mLastLocation.getLongitude()), 1)
.show();
}
}
#Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
}
Problem
In the above class I want to toast the current location. But it is not toasting anything. At least I need to see a toast saying "connected" on onConnected
event. Is there something wrong in my implementation?
Thanks in advance.
You seemingly never connect your client so it would be a real suprise if onConnected was called :)
You create your client with
client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
but for the client to do something you have to add:
client.connect();
getLastLocation() is going to give location only once. To get periodic location updates, you need to override onLocationChanged() method. You can get this Link
Best way that I found is simple implement you activity like so:
public class MapActivity extends Activity implements GoogleMap.OnMyLocationChangeListener
and override method
#Override
public void onMyLocationChange(Location location) {
mMap.addMarker(new MarkerOptions().position(location).icon(
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
}
And don't forget about mMap.setMyLocationEnabled(true); and mMap.setOnMyLocationChangeListener(this); in map init method
That's all!
Also, you can check is map available like here:
public boolean checkMapsAvailable() {
int isAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (isAvailable == ConnectionResult.SUCCESS) {
return true;
} else if (GooglePlayServicesUtil.isUserRecoverableError(isAvailable)) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(isAvailable, this, 9001);
dialog.show();
} else {
Constants.showToast(Constants.ALERT_GOOGLEPLAY_CONNECTION);
}
return false;
}
Hope this helps.

Update MapView/MapController from AsyncTask?

I'm making my first Android app, which on initial load determines the user's current location and goes to it in a MapView. I've delegated initializing the MapView/MapController to an AsyncTask to make the app feel more responsive, but I'm getting a RuntimeException in my doInBackground method. Here's the code for my initial Activity and the AsyncTask which I'm using.
public class MainActivity extends MapActivity {
Location latestLocation, targetLocation;
MapController mapController;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get a reference to the MapView
MapView myMapView = (MapView)findViewById(R.id.myMapView);
MapLoader map = new MapLoader();
try {
map.execute(myMapView).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
mapController = myMapView.getController();
//code which determines current location and animates to it in the Mapview.
}
}
And here's the code for my AsyncTask.
public class MapLoader extends AsyncTask<MapView ,Void, Void>{
MapController mapController;
MapView mapView;
#Override
protected Void doInBackground(MapView... params) {
// Get the Map View’s controller
mapController = params[0].getController();
// Configure the map display options
mapView.setSatellite(true);
mapView.displayZoomControls(false);
// Zoom in
mapController.setZoom(19);
return null;
}
}
Should I put the code for determining the location inside the AsyncTask as well? Currently, my app is pretty slow on loading, as well as being quite unresponsive even after everything's initialized.

Categories

Resources