Jump to content
Psycop

Android: OpenWeatherMap via Coordenadas GPS

Recommended Posts

Psycop

Bom Dia,

Estou a tentar fazer uma pequena aplicação que consuma a API OpenWeatherMap mas que use a localização do dispositivo para tal, as coordenadas.

Já consegui obter as coordenadas do dispositivo no entanto quando injecto essas mesmas coordenadas no URL para fazer a chamada ao serviço este não devolve informações, como se não tivessem sido introduzidas quaisquer coordenadas nos seus parametros.

Será que me podem ajudar?

Em baixo está o código que criei até agora:

public class MainActivity extends AppCompatActivity {

    private LocationManager locationManager;
    private LocationListener listener;

    static float lat;
    static float lon;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction().add(R.id.container, new WeatherFragment()).commit();
        }


        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);


        listener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                lat = (float)location.getLatitude();
                lon = (float)location.getLongitude();

                //t.setText("\n " + lat + "\n" + lon);
            }

            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) {

            }

            @Override
            public void onProviderEnabled(String s) {

            }

            @Override
            public void onProviderDisabled(String s) {

                Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(i);
            }
        };

        configure_button();


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.weather, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId() == R.id.change_city){
            showInputDialog();
        }
        return false;
    }

    private void showInputDialog(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Escolher a Cidade:");
        final EditText input = new EditText(this);
        input.setInputType(InputType.TYPE_CLASS_TEXT);
        builder.setView(input);
        builder.setPositiveButton("Go", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                changeCity(input.getText().toString());
            }
        });
        builder.show();
    }

    public void changeCity(String city){
        WeatherFragment wf = (WeatherFragment)getSupportFragmentManager()
                .findFragmentById(R.id.container);
        wf.changeCity(city);
        new CityPreference(this).setCity(city);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 10:
                configure_button();
                break;
            default:
                break;
        }
    }

    void configure_button(){
        // first check for permissions
        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_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.INTERNET}
                        ,10);
            }
            return;
        }
        // this code won't execute IF permissions are not allowed, because in the line above there is return statement.

        //noinspection MissingPermission
        locationManager.requestLocationUpdates("gps", 5000, 0, listener);
    }

}


RemoteFetch.java

 

public class RemoteFetch extends MainActivity{

    //private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric";


    //private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&units=metric";

    private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&lon=" + lon + "&units=metric";

    public static JSONObject getJSON(Context context, String city){
        try {
            URL url = new URL(String.format(OPEN_WEATHER_MAP_API, city));            
            HttpURLConnection connection = 
                    (HttpURLConnection)url.openConnection();
            
            connection.addRequestProperty("x-api-key", context.getString(R.string.open_weather_maps_app_id));
            
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()));
            
            StringBuffer json = new StringBuffer(1024);
            String tmp="";
            while((tmp=reader.readLine())!=null)
                json.append(tmp).append("\n");
            reader.close();
            
            JSONObject data = new JSONObject(json.toString());
            
            if(data.getInt("cod") != 200){
                return null;
            }
            
            return data;
        }catch(Exception e){
            return null;
        }
    }

}


WeatherFragment.java

public class WeatherFragment extends Fragment {
    
    Typeface weatherFont;
    
    TextView cityField;
    TextView updatedField;
    TextView detailsField;
    TextView currentTemperatureField;
    TextView weatherIcon;

    TextView windField;
    
    Handler handler;
    
    public WeatherFragment(){    
        handler = new Handler();
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_weather, container, false);
        cityField = (TextView)rootView.findViewById(R.id.city_field);
        updatedField = (TextView)rootView.findViewById(R.id.updated_field);
        detailsField = (TextView)rootView.findViewById(R.id.details_field);
        currentTemperatureField = (TextView)rootView.findViewById(R.id.current_temperature_field);
        weatherIcon = (TextView)rootView.findViewById(R.id.weather_icon);

        windField = (TextView)rootView.findViewById(R.id.wind_detail);
        
        weatherIcon.setTypeface(weatherFont);
        return rootView; 
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);  
        weatherFont = Typeface.createFromAsset(getActivity().getAssets(), "weather.ttf");
        updateWeatherData(new CityPreference(getActivity()).getCity());
    }
    
    private void updateWeatherData(final String city){
        new Thread(){
            public void run(){
                final JSONObject json = RemoteFetch.getJSON(getActivity(), city);
                if(json == null){
                    handler.post(new Runnable(){
                        public void run(){
                            Toast.makeText(getActivity(), 
                                    getActivity().getString(R.string.place_not_found), 
                                    Toast.LENGTH_LONG).show(); 
                        }
                    });
                } else {
                    handler.post(new Runnable(){
                        public void run(){
                            renderWeather(json);
                        }
                    });
                }                
            }
        }.start();
    }
    
    private void renderWeather(JSONObject json){
        try {
            cityField.setText(json.getString("name").toUpperCase(Locale.US) + 
                    ", " + 
                    json.getJSONObject("sys").getString("country"));
            
            JSONObject details = json.getJSONArray("weather").getJSONObject(0);
            JSONObject main = json.getJSONObject("main");
            detailsField.setText(
                    details.getString("description").toUpperCase(Locale.US) +
                    "\n" + "Humidity: " + main.getString("humidity") + "%" +
                    "\n" + "Pressure: " + main.getString("pressure") + " hPa");

            JSONObject wind = json.getJSONObject("wind");

            //converter para km/h
            double wind_ms = Double.parseDouble(wind.getString("speed").toUpperCase(Locale.getDefault()));
            double wind_km = wind_ms * 3.6;
            //DecimalFormat decimal = new DecimalFormat("#.##");
            //wind_km = Double.valueOf(decimal.format(wind_km));
            windField.setText("Wind: " + wind_km + " Km/h    ");


            currentTemperatureField.setText(
                        String.format("%.2f", main.getDouble("temp"))+ " ℃");

            DateFormat df = DateFormat.getDateTimeInstance();
            String updatedOn = df.format(new Date(json.getLong("dt")*1000));
            updatedField.setText("Last update: " + updatedOn);

            setWeatherIcon(details.getInt("id"),
                    json.getJSONObject("sys").getLong("sunrise") * 1000,
                    json.getJSONObject("sys").getLong("sunset") * 1000);
            
        }catch(Exception e){
            Log.e("SimpleWeather", "One or more fields not found in the JSON data");
        }
    }
    
    private void setWeatherIcon(int actualId, long sunrise, long sunset){
        int id = actualId / 100;
        String icon = "";
        if(actualId == 800){
            long currentTime = new Date().getTime();
            if(currentTime>=sunrise && currentTime<sunset) {
                icon = getActivity().getString(R.string.weather_sunny);
            } else {
                icon = getActivity().getString(R.string.weather_clear_night);
            }
        } else {
            switch(id) {
            case 2 : icon = getActivity().getString(R.string.weather_thunder);
                      break;         
            case 3 : icon = getActivity().getString(R.string.weather_drizzle);
                      break;        
            case 7 : icon = getActivity().getString(R.string.weather_foggy);
                     break;
            case 8 : icon = getActivity().getString(R.string.weather_cloudy);
                      break;
            case 6 : icon = getActivity().getString(R.string.weather_snowy);
                      break;
            case 5 : icon = getActivity().getString(R.string.weather_rainy);
                     break;
            }
        }
        weatherIcon.setText(icon);
    }
    
    public void changeCity(String city){
        updateWeatherData(city);
    }
}

No entanto se injectar manualmente umas coordenadas válidas no URL obtenho a respetiva resposta do serviço, pelo que prevejo que o problema esteja na obtenção das coordenadas do dispositivo e a sua injecção on time no URL do serviço.

Da a sensação que as coordenadas obtidas pelo location não estão a ser injetadas em tempo útil para o pedido do URL ao serviço.

Alguém me consegue ajudar a resolver este problema?

Cumprimentos

Edited by Psycop

Share this post


Link to post
Share on other sites
Psycop

Tenho tentado perceber o que está a acontecer, e a conclusão a que chego é que no momento de executar o pedido a API do OpenWeatherMap o sistema ainda não obteve as coordenadas do dispotivo de modo a injecta-las no URL e de seguida este fazer o pedido já com as coordenadas do local...

Agora o meu grande problema está em como contornar esta situação.

Alguma ideia para me ajudar a resolver esta situação?

Share this post


Link to post
Share on other sites
apocsantos

Boa noite,

@Psycop, assim "out of the top", uma vez que o problema está na demora de obtenção de coordenadas do device, a quando do pedido ao OpenWeatherMap, porque não usar uma AsyncTask(); , e apenas quando ela estiver concluída executar o pedido ao OpenWeatherMap ?

 

private class GetWeatherTask extends AsyncTask<String, Void, String> {
    private TextView textView;
 
    public GetWeatherTask(TextView textView) {
        this.textView = textView;
    }
 
    @Override
    protected String doInBackground(String... strings) {
        return null;
    }
 
    @Override
    protected void onPostExecute(String temp) {
        textView.setText("Clima actual: " + temp);
    }
}

 

@Override
protected String doInBackground(String s1, s2) {
    String weather = "UNDEFINED";
    try {
        URL url = new URL(strings[0]);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
 
        InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
        StringBuilder builder = new StringBuilder();
 
        String inputString;
        while ((inputString = bufferedReader.readLine()) != null) {
            builder.append(inputString);
        }
 
        JSONObject topLevel = new JSONObject(builder.toString());
        JSONObject main = topLevel.getJSONObject("main");
        weather = String.valueOf(main.getDouble("temp"));
 
        urlConnection.disconnect();
    } catch (IOException | JSONException e) {
        e.printStackTrace();
    }
    return weather;
}

e por fim no onCreate() executas a seguinte:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    double lat = 41.432088, lon = -8.494201; //o antigo radar dos aviões, que voavam muito alto! :D
    String units = "Metric";
    String url = String.format("http://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&units=%s&appid=%s",
            lat, lon, units, APP_ID);
 
    TextView textView = (TextView) findViewById(R.id.textView);
    new GetWeatherTask(textView).execute(url);
}

Cordiais cumprimentos,

Apocsantos

 


"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.