I'm building a simple five-day weather forecast Android app using the open weather map API. I am trying to insert the user coordinates into my request URL using the Google Play Services but values for latitude and longitude are null when I am passing them into the URL. I am just wondering if there is any way to solve this by passing the coordinates from the onConnected methods of the Google Play Services.
MainActivity
public class MainActivity extends AppCompatActivity implements OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private String latitude;
private String longitude;
private String requestUrl = "http://api.openweathermap.org/data/2.5/forecast?lat="+latitude+"&lon="+longitude+"&units=metric&APPID={insert api key here}";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of GoogleAPIClient.
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
new WeatherAsyncTask().execute(requestUrl);
}
public void updateUi(final ArrayList<Weather> weather) {
// Find a reference to the {#link ListView} in the layout
ListView weatherListView = (ListView) findViewById(R.id.list);
// Create a new {#link ArrayAdapter} of earthquakes
WeatherAdapter adapter = new WeatherAdapter(this, weather);
// Set the adapter on the {#link ListView}
// so the list can be populated in the user interface
weatherListView.setAdapter(adapter);
}
private class WeatherAsyncTask extends AsyncTask<String, Void, ArrayList<Weather>> {
protected ArrayList<Weather> doInBackground(String... requestUrl) {
// Dont perform the request if there is no URL, or first is null
if (requestUrl.length < 1 || requestUrl[0] == null) {
return null;
}
ArrayList<Weather> weather = QueryUtils.fetchWeatherData(requestUrl[0]);
return weather;
}
protected void onPostExecute(ArrayList<Weather> weather) {
// if there is no result do nothing
if (weather == null) {
return;
}
updateUi(weather);
}
}
// if connection not established to google play services
#Override
public void onConnectionFailed(ConnectionResult result) {
// An unresolvable error has occurred and a connection to Google APIs
// could not be established. Display an error message, or handle
// the failure silently
// ...
}
// get latitude and longitude of last known location when connected to google play services
public void onConnected(Bundle connectionHint) {
try {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} catch (SecurityException e) {
Log.e("MainActivity", "Security exception thrown", e);
}
if (mLastLocation != null) {
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
}
}
}
When the app is run, I get a NullPointerException. I realize that the values for latitude and longitude are null but I am not sure how to retrieve them correctly. Thanks for any help, I'm fairly new at android development.
P.S. I have omitted the API key from the URL
Please refer this guide : Retrieving-Location-with-LocationServices-API
First of all LocationServices.FusedLocationApi.getLastLocation will return you a location if any recent app used location(device has recent location) otherwise it will return null.
So in case of null value you must check it inside onConnected .
For getting non null location you must listen devices location.(FusedLocationApi, LocationManager ...)
Also you must check permission for Android M higher devices, luckily you are using FusedLocationApi inside your Activity.
Basic sample of my code :
#Override
public void onConnected(#Nullable Bundle bundle) {
if( HelperUtils.isGpsOpen(getApplicationContext()) ) {
startListenLocation();
}
}
#Override
public void startListenLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//ask permission whatever you want to do
} else {
if(mGoogleApiClient==null) {
buildGoogleApiClient();
} else {
if(mGoogleApiClient.isConnected()) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
Location mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
//here I am checking null thats where you get null
if(mCurrentLocation!=null) {
mPresenter.onNewLocation(getDeviceId(),mCurrentLocation.getLatitude(),mCurrentLocation.getLongitude());
}
// then I am tracking user location , this will trigger onLocationChanged method when a new location arrived so you can handle new location
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} else {
if(!mGoogleApiClient.isConnecting())
buildGoogleApiClient();
}
}
}
}
#Override
public void onLocationChanged(Location location) {
// I am just checking null again, more cautious I am :)
if(location!=null) // handle it
}
Then important part is remove location requests when your Activity's onPause or onDestroy :
if(mGoogleApiClient!=null){
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
if(mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect();
}
Related
The first time I install this application, and when I launch MapsActivity, I am asked for permissions, which is normal. But the problem is that the application closes in the meantime. How can I modify my code to keep the application open, and the permission pop-up just overlaps. Thank you very much for your answer.
Error code in logcat :
2020-02-02 11:17:01.340 11559-11574/? E/le.rsr_pechhlu: Unable to peek into adb socket due to error. Closing socket.: Connection reset by peer
2020-02-02 11:17:01.470 11559-11636/? E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile#2f88384
2020-02-02 11:17:01.470 11559-11636/? E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile#7fa676d
2020-02-02 11:17:01.471 11559-11603/? E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
2020-02-02 11:17:10.787 11559-11559/com.example.rsr_pechhlup E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.rsr_pechhlup, PID: 11559
java.lang.RuntimeException: Unable to pause activity {com.example.rsr_pechhlup/com.example.rsr_pechhlup.MapsActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.location.LocationManager.removeUpdates(android.location.LocationListener)' on a null object reference
at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4742)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4691)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4626)
at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
at android.os.Handler.dispatchMessage(Handler.java:112)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7625)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.location.LocationManager.removeUpdates(android.location.LocationListener)' on a null object reference
at com.example.rsr_pechhlup.MapsActivity.onPause(MapsActivity.java:159)
at android.app.Activity.performPause(Activity.java:7663)
at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1536)
at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4726)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4691)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4626)
at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
at android.os.Handler.dispatchMessage(Handler.java:112)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7625)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
public class MapsActivity extends FragmentActivity implements LocationListener {
private GoogleMap googleMap; //google map is contained in the fragment work on it to change the position of the map and so on.
private Marker marker;
private Button buttonCallNow;
private RelativeLayout callPanelWrapper;
private static final int PERMS_CALL_ID = 1234; //permission identifier, unique identifier
private static final int REQUEST_PHONE_CALL = 4321;
private LocationManager locationManager; // Android manager service of android platform.
private SupportMapFragment mapFragment;
private Utils utils;
private PhoneCallListener phoneCallListener;
private boolean firstTime;
private String adresse;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps2);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mapFragment= (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
}
/**
* //When the activity comes back to the foreground, I have to subscribe to the different location information providers, so I will receive the new location information and I will be able to resynchronize my mapping on this location.
*/
#Override
protected void onResume() {
super.onResume();
checkPermissions();
firstTime=true;
}
private void checkPermissions(){
//For older versions of android we check that the ACCES_FINE_LOCATION and ACCES_COARSE_LOCATION permissions are enabled.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION },PERMS_CALL_ID); //We must provide three parameters: it is the activity that requires the activation of these permissions (here it is this), then a table that specifies the set of permissions to allow. And we need a request code.
return;
}
locationManager= (LocationManager) getSystemService(LOCATION_SERVICE);//I ask android to give me that service locationManager. LOCATION SERVICE comes inheritance FragmentActivity, which inherits from Context, which contains this constant.
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){//If on this locationManager, a particular provider here : LocationManager.GPS_PROVIDER is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
if(locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER)){//If on this locationManager, a particular provider here : LocationManager.PASIVE_PROVIDER is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){//If on this locationManager, a particular provider here : NETWORK is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
dispMap();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==PERMS_CALL_ID){ //This method will be activated each time a permission request is made. And to know where I'm coming from I need the requestCode. This request is coupled with this requestCode here.
checkPermissions(); //i call again chack permission do disp again pop-up permission.
}
}
/**
* //When my application leaves the foreground, I unsubscribe from the different providers of location information so as not to consume a lot of resources.
*/
#Override
protected void onPause() {
super.onPause();
//If the locationManager has been initialized, I make one of this, one of the earphone of all suppliers
locationManager.removeUpdates(this);
}
private void dispMap(){
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
MapsActivity.this.googleMap=googleMap;
marker = googleMap.addMarker(new MarkerOptions().position(new LatLng(43.799345,6.725426)));
}
});
}
/**
* React each time new positioning information is calculated
* #param location
*/
#Override
public void onLocationChanged(Location location) { //This location is obtained through the provider. Of course this can be any provider, GPS_PROVIDER is more accurate than PASSIVE_PROVIDER etc..
double latitude= location.getLatitude();//I'm getting the latitude.
double longitude=location.getLongitude();// I'm getting the longitude.
Toast.makeText(this, "Location: " + latitude + "/" + longitude,Toast.LENGTH_SHORT).show();
LatLng googleLocation=new LatLng(latitude,longitude);
if(firstTime){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleLocation, 16.2f));
adresse= Utils.getCompleteAddressString(latitude, longitude,this);
BitmapDescriptor subwayBitmapDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.map_marker);
marker = googleMap.addMarker(new MarkerOptions().position(googleLocation).icon(subwayBitmapDescriptor).title(adresse));
googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(this));
}
firstTime=false;
if(this.googleMap!=null){//If my map is correctly displayed
adresse = Utils.getCompleteAddressString(latitude, longitude,this);
googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(this));
marker.setTitle(adresse);
marker.setPosition(googleLocation);
marker.showInfoWindow();
}
}
/**
* To react to every change of state
* #param provider
* #param status
* #param extras
*/
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
/**
* When a location provider is closed.
* #param provider
*/
#Override
public void onProviderEnabled(String provider) {
}
/**
* When a location provider is closed.
* #param provider
*/
#Override
public void onProviderDisabled(String provider) {
}
public void btnBackClick(View view) {
Intent myIntent = new Intent(this, HomeActivity.class);
startActivity(myIntent);
}
public void btnCallMapclicked(View view) {
callPanelWrapper.setVisibility(View.VISIBLE);
buttonCallNow.setVisibility(View.GONE);
}
public void buttonFinalCallClicked(View view) {
call();
}
public void popupClosedClicked(View view) {
callPanelWrapper.setVisibility(View.GONE);
buttonCallNow.setVisibility(View.VISIBLE);
}
}
}
I'm not able to put comment,Thus forward my answer as post.
you may should describe about your problem more but do you add ACCESS_FINE_LOCATION and
ACCESS_COARSE_LOCATION to your Manifest file?
EDIT:
just change onPause to following:
#Override
protected void onPause() {
super.onPause();
if(locationManager != null) // add this line to your code
locationManager.removeUpdates(this);
}
Cause:
When Permission dialog has been shown your activity onPause() is called, and since you not initialize location manager yet, it throws NullPointerException.
Try this code to initialize map with required run time permission.
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback,
GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onMapReady(GoogleMap googleMap) {
Toast.makeText(this, "Map is Ready", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onMapReady: map is ready");
mMap = googleMap;
if (mLocationPermissionsGranted) {
getDeviceLocation();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
init();
}
}
private static final String TAG = "MapActivity";
private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
//vars
private Boolean mLocationPermissionsGranted = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
getLocationPermission();
}
private void initMap(){
Log.d(TAG, "initMap: initializing map");
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(MapActivity.this);
}
private void getLocationPermission(){
Log.d(TAG, "getLocationPermission: getting location permissions");
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION};
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
COURSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = true;
initMap();
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult: called.");
mLocationPermissionsGranted = false;
switch(requestCode){
case LOCATION_PERMISSION_REQUEST_CODE:{
if(grantResults.length > 0){
for(int i = 0; i < grantResults.length; i++){
if(grantResults[i] != PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = false;
Log.d(TAG, "onRequestPermissionsResult: permission failed");
return;
}
}
Log.d(TAG, "onRequestPermissionsResult: permission granted");
mLocationPermissionsGranted = true;
initMap(); // once permission granted then only initMap()
}
}
}
}
}
I have been working on an app which implements google maps. When I am on my homescreen and presses the "start map" button the message "Skipped 85 frames! The application may be doing too much work on its main thread." is shown in the Android Monitor. I have been looking around for a solution but have not been able to find one that works for me. Does anyone have any idea how to prevent this?
My maps activity:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private GoogleMap mMap;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
LocationRequest mLocationRequest;
private boolean initiateApp;
double CO2data = 1.02;
double N2data = 0.002;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission();
}
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
initiateApp = true;
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Initialize Google Play Services
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
/* Here we create the infoWindow **/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
public View getInfoWindow(Marker arg0) {
View v = getLayoutInflater().inflate(R.layout.custom_infowindow, null);
TextView tv = (TextView) v.findViewById(R.id.infoText);
tv.setText("CO2 data: "+String.valueOf(CO2data) +"\n" + "N2 data: "+String.valueOf(N2data));
return v;
}
public View getInfoContents(Marker arg0) {
return null;
}
});
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(2000);
mLocationRequest.setFastestInterval(2000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
Log.d("ADebugTag", "Value: " + Double.toString(location.getLatitude()));
Log.d("ADebugTag", "Value: " + Double.toString(location.getLongitude()));
//move map camera
if(initiateApp){
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
}
initiateApp = false;
boolean contains = mMap.getProjection()
.getVisibleRegion()
.latLngBounds
.contains(latLng);
if(!contains){
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission(){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Asking user if explanation is needed
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted. Do the
// contacts-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
} else {
// Permission denied, Disable the functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other permissions this app might request.
// You can add here other case statements according to your requirement.
}
}
}
My maps XML
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.kasper.map_app.MapsActivity" />
Based from this thread, if you have a lot of code in your UI events then you will see this error message. Also this will occur with asynchronous events like fetching data from a URL. The workaround given is to use threads or async tasks.
You want to off load any heavy code off of your UI Threads and onto another area - a new thread or in your main activity.
Here are some SO posts which might also help:
The application may be doing too much work on its main thread
The application may be doing too much work on its main thread - Android
After updated my app to support Android 7 the GPS listner no longer is invoked when the GPS on/off is triggerd. If I refresh my activity it works as expected on Android 6, but not in Android 7. Does anyone have any idea. I have added both my listner, and code releated to gps change in my activity.
I have if its difficult a theory to override the backpressed or activity resumed to recreate view, but havn't suceeded with that either .
GPSListner.java
public abstract class GPSListener implements LocationListener {
private Context context;
public GPSListener(Context context) {
this.context = context;
}
#Override
public void onProviderEnabled(String provider) {
onGPSOn();
}
#Override
public void onProviderDisabled(String provider) {
onGPSOff();
}
public abstract void onGPSOff();
public abstract void onGPSOn();
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
My class
gpsListener = new GPSListener(this) {
#Override
public void onGPSOff() {
gpsImg.setImageResource(R.drawable.notok);
}
#Override
public void onGPSOn() {
gpsImg.setImageResource(R.drawable.ok);
}
};
final LocationManager manager;
manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
final ImageView gpsImg = (ImageView) findViewById(R.id.gpsstatus);
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
gpsImg.setImageResource(R.drawable.ok);
} else {
gpsImg.setImageResource(R.drawable.notok); //not ok
}
This last method opens the gps settings.
public View.OnClickListener onButtongpsClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent gpsOptionsIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(gpsOptionsIntent);
}
};
Obtaining location is a bit tricky itself. Only GPS can have line-of-sight issues and would vary depending on device too, not just Android version. Over the years Android location services have matured and using up-to-date standard practices does result in higher consistency with respect to results.
By the way, LocationClient is deprecated. FusedLocationProviderApi does not use it anymore.
It works through a GoogleApiClient and this part makes the GooglePlayServices mandatory. You have options if this does not suit your app.
Making your app location aware suggests:
The Google Play services location APIs are preferred over the Android
framework location APIs (android.location) as a way of adding location
awareness to your app. If you are currently using the Android
framework location APIs, you are strongly encouraged to switch to the
Google Play services location APIs as soon as possible.
You can break it into parts to understand it better, like;
Building the GoogleApiClient
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this) //this = activity
.addApi(LocationServices.API)
.addConnectionCallbacks(this) //interfaces implemented
.addOnConnectionFailedListener(this)
.build();
}
Requesting location,
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
Try the last known location, if that requirement works for you,
#Override
public void onConnected(Bundle bundle) {
Location mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
...}
onConnected() is the callback from GoogleApiClient...
So there is more to location than initialising a client and implementing the listener. I recommend you go through a few questions or android docs to ensure you implement what suits your requirement.
Also,
instead of
Intent gpsOptionsIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); ,
use SettingsApi
can refer to Enabling location mode...
Some useful Q&As:
Comprehensive answer for obtaining location
Good to go through LocationRequest part here if you want to avoid reading in detail
final LocationManager manager;
manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Do i even have to comment on this one? Read it again and you will understand what is wrong with it.
Hint. Try:
final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
You can used fused location api to get the location
Fused Location Api :
Fused Location Provider automatically decides best location from the available options for that it uses GPS and Network Provider, So if the device GPS is off we can still get the location from Network provider vice versa.
Why Fused Location Api ?
Consumption of power while fetching location.
It will give accurate
location based on user priority.
Piggyback which means you can get
location every time when other application hits for location for you
advantage is user not blame you for that you just getting those
location which other application request.
We don’t have to pick the
provider(GPS or network provider)
please refer code for following for getting location.
LocationService : We required these for getting continues location and these register as pending intent so whenever device got new location these service invoke.
public class LocationService extends IntentService {
private String TAG = this.getClass().getSimpleName();
public LocationService() {
super("Fused Location");
}
public LocationService(String name) {
super("Fused Location");
}
#Override
protected void onHandleIntent(Intent intent) {
Location location = intent.getParcelableExtra(LocationClient.KEY_LOCATION_CHANGED);
if(location !=null){
Log.i(TAG, "onHandleIntent " + location.getLatitude() + "," + location.getLongitude());
// write your code here.
}
}
}
MainActivity : which register callbacks for it which tell us whether we are connected or disconnected with api.
public class MainActivity extends Activity implements GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {
private String TAG = this.getClass().getSimpleName();
private LocationClient locationclient;
private LocationRequest locationrequest;
private Intent mIntentService;
private PendingIntent mPendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntentService = new Intent(this,LocationService.class);
mPendingIntent = PendingIntent.getService(this, 1, mIntentService, 0);
int resp =GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resp == ConnectionResult.SUCCESS){
locationclient = new LocationClient(this,this,this);
locationclient.connect();
}
else{
Toast.makeText(this, "Google Play Service Error " + resp, Toast.LENGTH_LONG).show();
}
}
public void buttonClicked(View v){
if(v.getId() == R.id.btnLastLoc){
if(locationclient!=null && locationclient.isConnected()){
Location loc =locationclient.getLastLocation();
Log.i(TAG, "Last Known Location :" + loc.getLatitude() + "," + loc.getLongitude());
txtLastKnownLoc.setText(loc.getLatitude() + "," + loc.getLongitude());
}
}
if(v.getId() == R.id.btnStartRequest){
if(locationclient!=null && locationclient.isConnected()){
if(((Button)v).getText().equals("Start")){
locationrequest = LocationRequest.create();
locationrequest.setInterval(Long.parseLong(etLocationInterval.getText().toString()));
locationclient.requestLocationUpdates(locationrequest, this);
((Button) v).setText("Stop");
}
else{
locationclient.removeLocationUpdates(this);
((Button) v).setText("Start");
}
}
}
if(v.getId() == R.id.btnRequestLocationIntent){
if(((Button)v).getText().equals("Start")){
locationrequest = LocationRequest.create();
locationrequest.setInterval(100);
locationclient.requestLocationUpdates(locationrequest, mPendingIntent);
((Button) v).setText("Stop");
}
else{
locationclient.removeLocationUpdates(mPendingIntent);
((Button) v).setText("Start");
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(locationclient!=null)
locationclient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "onConnected");
txtConnectionStatus.setText("Connection Status : Connected");
}
#Override
public void onDisconnected() {
Log.i(TAG, "onDisconnected");
txtConnectionStatus.setText("Connection Status : Disconnected");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed");
txtConnectionStatus.setText("Connection Status : Fail");
}
#Override
public void onLocationChanged(Location location) {
if(location!=null){
Log.i(TAG, "Location Request :" + location.getLatitude() + "," + location.getLongitude());
}
}
}
For more reference refer below link
https://github.com/riteshreddyr/fused-location-provider
https://github.com/kpbird/fused-location-provider-example
Hope these help you.
My objective is to track the user's location and give an alert on reaching marked location. So first I get the location to reach and marked that. Then I get the current location and compare it with marked location. But it is not working. Even I placed the marker at current location. It is not giving the toast message. Here is the code -
public class MainActivity extends FragmentActivity implements LocationListener{
LocationManager locationManager;
String provider;
ToggleButton toggle;
public static double lat,lang,value1,value2,value3,value4;
public static String strlat,strlat1;
public LatLng loc,loc1;
public double latitude,longitude;
public static String strlang,strlang1 ;
Location location;
public LocationManager locationmanager;
// Google Map
private GoogleMap googleMap;
LocationListener Locationlistener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
// Creating an empty criteria object
Criteria criteria = new Criteria();
// Getting the name of the provider that meets the criteria
provider = locationManager.getBestProvider(criteria, false);
if(provider!=null && !provider.equals("")){
// Get the location from the given provider
final Location location = locationManager.getLastKnownLocation(provider);
locationManager.requestLocationUpdates(provider, 1000, 1, this);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
if(location!=null){
lat = location.getLatitude();
lang = location.getLongitude();
value3 =Double.parseDouble(new DecimalFormat("##.##").format(lat));
value4 =Double.parseDouble(new DecimalFormat("##.##").format(lang));
strlat = String.valueOf(value3);
strlang = String.valueOf(value4);
loc1 =new LatLng(lat, lang);
if((value1 == value3) && (value2 == value4))
{
Toast.makeText(getApplicationContext(), "target reached", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(getBaseContext(), "Location can't be retrieved", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getBaseContext(), "No Provider Found", Toast.LENGTH_SHORT).show();
}
handler.postDelayed(this, 1000);
}
};
handler.post(runnable);
}
try {
// Loading map
initilizeMap();
// Changing map type
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
// googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
// googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
// googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
// googleMap.setMapType(GoogleMap.MAP_TYPE_NONE);
// Showing / hiding your current location
googleMap.setMyLocationEnabled(true);
// Enable / Disable zooming controls
googleMap.getUiSettings().setZoomControlsEnabled(false);
// Enable / Disable my location button
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
// Enable / Disable Compass icon
googleMap.getUiSettings().setCompassEnabled(true);
// Enable / Disable Rotate gesture
googleMap.getUiSettings().setRotateGesturesEnabled(true);
// Enable / Disable zooming functionality
googleMap.getUiSettings().setZoomGesturesEnabled(true);
// create marker
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(loc, 16.0f));
} catch (Exception e) {
e.printStackTrace();
}
googleMap.setOnMapClickListener(new OnMapClickListener(){
public void onMapClick(LatLng point){
Toast.makeText(getBaseContext(),
point.latitude + ", " + point.longitude,
Toast.LENGTH_LONG).show();
latitude = point.latitude;
longitude = point.longitude;
value1 =Double.parseDouble(new DecimalFormat("##.##").format(latitude));
value2 =Double.parseDouble(new DecimalFormat("##.##").format(longitude));
strlat1 = String.valueOf(value1);
strlang1 = String.valueOf(value2);
loc=new LatLng(point.latitude, point.longitude);
MarkerOptions marker = new MarkerOptions().position(loc).title("Hello Maps ");
// adding marker
googleMap.addMarker(marker);
}
});
}
#Override
protected void onResume() {
super.onResume();
initilizeMap();
}
/**
* function to load map If map is not created it will create it for you
* */
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
}
}
/*
* creating random position around a location for testing purpose only
*/
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
}
There are a few things wrong in your code.
You can't compare coordinates with == because you will never have an exact match for lat/lon coordinates when tracking the device's location. You need to figure out a threshold, and if the device gets within that threshold, then show the alert.
Next, you're not using your onLocationChanged() callback, so you are just looking at the current location one time at app start-up.
Take a look at the code in my other answer here which is about determining if the device is within a circle. This is a similar problem.
So, if you were to make your threshold 10 meters, and consider the target reached if the device is within 10 meters of the target location, you would implement your onLocationChanged() method something like this:
#Override
public void onLocationChanged(Location location) {
float[] distance = new float[2];
Location.distanceBetween( location.getLatitude(), location.getLongitude(),
latitude, longitude, distance);
if( distance[0] < 10 ){
//target location reached
Toast.makeText(getApplicationContext(), "target reached", Toast.LENGTH_SHORT).show();
}
}
one more daniel.i changed above code now it was working now have some more problem.
1.i tried to set splash screen like in my second.class.i set the above code for google map.it was running for five second while moving from one to another it get stopped
new Timer().schedule(new TimerTask(){
public void run() {
Intent intent = new Intent (MainActivity.this, SecondActivity.class);
PendingIntent pendIntent = PendingIntent.getActivity(getBaseContext(), 1000, intent, 0);
}
}, 5000);
2.i want set search in google map how to set that i tried that it not working give some idea.
My app is heavily run off GeoCoordinates, and I have it so when users Post a Book it records the users geo coordinate like so:
PostBookButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locationListener = new ObtainLocation();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
});
public class ObtainLocation implements LocationListener{
#Override
public void onLocationChanged(Location loc) {
if (loc != null)
{
Latitude = loc.getLatitude();
Longitude = loc.getLongitude();
ParseGeoPoint itemLoc = new ParseGeoPoint(Latitude,Longitude);
book.setGeoLocation(itemLoc);
book.saveInBackground(new SaveCallback()
{
#Override
public void done(ParseException e) {
if (e == null)
{
finish();
}
else
{
}
}
});
}
}
else
{
}
locationManager.removeUpdates(locationListener);
}
But problem is app will crash if the activity is ran with no network connection, seeing how it won't be able to obtain the geopoint coordinates.
How would I just make it so if the app fails on obtaining coordinates, instead of crashing maybe alert the user they cannot view books in their area due to no way to obtain their current location.
Update: The solution below is a general network connectivity one and won't necessarily tell you if you can get location updates through wifi as pointed out in comments.
You can register to receive network connectivity updates using a BroadcastReceiver. Register to listen for the android.net.conn.CONNECTIVITY_CHANGE action. Take a look at this for more info. Below, is a sample receiver.
public class ConnectivityReceiver extends WakefulBroadcastReceiver {
private static final String TAG = ConnectivityReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected()) {
Log.d(TAG, "network state change; new state: connected");
} else {
Log.d(TAG, "network state change; new state: " + (cm.getActiveNetworkInfo() != null ? cm.getActiveNetworkInfo().getState() : " unknown"));
}
}
}
In addition to checking network accessibility, check if network location provider is enabled by user's system preferences:
ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if ( lm == null || cm == null
|| !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
|| !cm.getActiveNetworkInfo().isConnected()) {
// show alert: geolocation through network is inaccessible
}