Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialalekseibingham
4,491 PointsI want to receive gps coordinates first thing but instead my latitude and longitude are being passed through as 0.
package com.example.aleksei.stormy;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.PermissionChecker;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.location.Geocoder;
import com.example.aleksei.stormy.databinding.ActivityMainBinding;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private CurrentWeather currentWeather;
private ImageView iconImage;
private LocationManager locationManager;
private LocationListener locationListener;
private ProgressDialog progressDialog;
private double latitude;
private double longitude;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s)
{
}
@Override
public void onProviderDisabled(String s) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET}, 10);
return;
}
}
else
{
locationManager.requestLocationUpdates("gps", 0000, 0, locationListener);
}
String currentCity = currentLocation(latitude, longitude);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Obtaining your geo location via gps");
while (currentCity == null)
{
progressDialog.show();
}
progressDialog.dismiss();
getForecast(latitude, longitude, currentCity);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 10:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
locationManager.requestLocationUpdates("gps", 0000, 0, locationListener);
}
}
}
//Get the nearest city name
private String currentLocation(double latitude, double longitude)
{
String currentCity = "";
Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
List<Address> addressList;
try
{
addressList = geocoder.getFromLocation(latitude, longitude, 1);
if (addressList.size() > 0)
{
currentCity = addressList.get(0).getLocality();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return currentCity;
}
private void getForecast(double latitude, double longitude, final String currentCity) {
final ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);
TextView darkSky = findViewById(R.id.darkSkyAttribution);
//Used to check for clicking links
darkSky.setMovementMethod(LinkMovementMethod.getInstance());
String apiKey = "e3386b28e1ae72def9071a009d5fa1e2";
iconImage = findViewById(R.id.iconImageView);
if (isNetworkAvailable())
{
String forecastUrl = "https://api.darksky.net/forecast/" + apiKey + "/" + latitude + "," + longitude;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(forecastUrl).build();
Call call = client.newCall(request);
call.enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
try {
String jsonData = response.body().string();
Log.v(TAG, jsonData);
if (response.isSuccessful())
{
currentWeather = getCurrentDetails(jsonData, currentCity);
final CurrentWeather displayWeather = new CurrentWeather(
currentWeather.getLocationLabel(),
currentWeather.getIcon(),
currentWeather.getTime(),
currentWeather.getTemperature(),
currentWeather.getHumidity(),
currentWeather.getPrecipChance(),
currentWeather.getSummary(),
currentWeather.getTimeZone()
);
binding.setWeather(displayWeather);
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Drawable drawable = getResources().getDrawable(displayWeather.getIconId());
iconImage.setImageDrawable(drawable);
}
});
}
else
{
alertUserAboutError();
}
}
catch (IOException e)
{
Log.e(TAG, "IO Exception caught: ", e);
}
catch (JSONException e)
{
Log.e(TAG, "JSON Exception Caught: ", e);
}
}
});
}
else
{
alertUserAboutNetworkError();
}
}
private CurrentWeather getCurrentDetails(String jsonData, String currentCity) throws JSONException
{
JSONObject forecast = new JSONObject(jsonData);
String timezone = forecast.getString("timezone");
Log.i(TAG, "From JSON: " + timezone);
JSONObject currently = forecast.getJSONObject("currently");
CurrentWeather currentWeather = new CurrentWeather();
currentWeather.setHumidity(currently.getDouble("humidity"));
currentWeather.setTime(currently.getLong("time"));
currentWeather.setIcon(currently.getString("icon"));
currentWeather.setLocationLabel(currentCity);
Log.i(TAG, "currentCity Value: " + currentCity);
currentWeather.setPrecipChance(currently.getDouble("precipProbability"));
currentWeather.setSummary(currently.getString("summary"));
currentWeather.setTemperature(currently.getDouble("temperature"));
currentWeather.setTimeZone(timezone);
return currentWeather;
}
private void alertUserAboutNetworkError()
{
NetworkDialogError dialog = new NetworkDialogError();
dialog.show(getFragmentManager(), "error_dialog");
}
private boolean isNetworkAvailable()
{
ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected())
{
return true;
}
//Toast.makeText(this, R.string.network_unavailable_message, Toast.LENGTH_LONG).show();
return false;
}
private void alertUserAboutError()
{
AlertDialogFragment dialog = new AlertDialogFragment();
dialog.show(getFragmentManager(), "error_dialog");
}
public void refreshOnClick(View view)
{
Toast.makeText(this, "Refreshing Data", Toast.LENGTH_LONG).show();
String currentCity = currentLocation(latitude, longitude);
getForecast(latitude, longitude, currentCity);
}
}
This is the completed weather app's MainActivity file. I am new to the gps features that I tried implementing myself near the top. The app will correctly receive information from the Dark Sky Api only after refreshing at least once. Using the debugger I can see that latitude and longitude are 0 until I hit refresh causing the currentCity string to be empty. This is all vital data to receiving user location upon the app launching.
All help is much appreciated as I have spent hours trying to solve this issue.
2 Answers
Seth Kroger
56,413 PointsWhat you need to do is to wait for the first location update. Unfortunately the approach you're using:
String currentCity = currentLocation(latitude, longitude);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Obtaining your geo location via gps");
while (currentCity == null)
{
progressDialog.show();
}
progressDialog.dismiss();
getForecast(latitude, longitude, currentCity);
1) Won't work because the while loop will tie up the main thread and cause the UI to freeze or crash from repeatedly showing a dialog, 2) currentCity is never null (your currentLocation method always returns a valid String, even if it's an empty one) so the while loop won't run. 3) currentCity is never updated so the while loop is either a nothing loop or an infinite loop.
A much better approach would be to wait for the onLocationChanged() to be called, then determine if it is the first update and call getForecast() from there.
Steve Hunter
57,712 PointsHi there,
I got this working some years ago - I don't know if this old code will still work on newer Android versions. This pulls the lat & long from the GPS and displays the name of the nearest town too.
Have a look around line 303 of MainActivity for my implementation of this, here.
Good luck!
Steve.
alekseibingham
4,491 PointsThank you so much I will give it a try! Im going to wait on giving it best answer until I hopefully get more attention.
alekseibingham
4,491 Pointsalekseibingham
4,491 PointsThis information is fantastic and I do understand that currentCity is never null. I actually had it removed after using the debugger and learning I am still receiving an empty string.
Now im wondering how I can determine when the onLocationChanged() is called and how to determine like you said, if its the first update. As far as I know it checks every so many seconds and if the distance is greater then the old distance the method is called.
Thanks again for everything this is absolutely amazing to get feedback here!