-2

I would like create Android meteo app. So, I use web API to get weather with HttpURLConnection method:

package com.example.monlouis.myapplication;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class WeatherAPI {

/*
    Liste des informations utiles à récupérer :

    Température actuelle Kelvin : main->temp
    Température min Kelvin : main->temp_min
    Température max Kelvin : main->temp_max
    Humidité actuelle : main->humidity
    Coordonnées GPS (longitude) : coord->lon
    Coordonnées GPS (latitude) : coord->lat
    Nom de la ville : name
    Pays : sys->country
    Description courte du temps : weather->0->main
    Description longue du temps : weather->0->description
*/

private static String API_URL = "http://api.openweathermap.org/data/2.5/weather";
private static String API_KEY = "b1b15e88fa797225412429c1c50c122a1";

// Recherche de la météo par code postal + code du pays (fr, en...)
public String getWeatherByZipCode(String zipCode, String countryCode) {
    HttpURLConnection con = null;
    InputStream is = null;
    try {
        con = (HttpURLConnection) ( new URL(API_URL + "?zip=" + zipCode + "," + countryCode + "&appid=" + API_KEY)).openConnection();
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();
        StringBuffer buffer = new StringBuffer();
        is = con.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;
        while( (line = br.readLine()) != null) {
            buffer.append(line + "\r\n");
        }
        is.close();
        con.disconnect();
        return buffer.toString();
    }
    catch(Throwable t) {
        t.printStackTrace();
    }
    finally {
        try { is.close(); } catch(Throwable t) {}
        try { con.disconnect(); } catch(Throwable t) {}
    }
    return null;
}

// Recherche de la météo par nom de la ville + code du pays (fr, en...)
public static String getWeatherByCityName(String cityName, String countryCode) {
    HttpURLConnection con = null;
    InputStream is = null;
    try {
        System.out.println(cityName);
        System.out.println(countryCode);
        con = (HttpURLConnection) ( new URL(API_URL + "?q=" + cityName + "," + countryCode + "&appid=" + API_KEY)).openConnection();
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();
        StringBuffer buffer = new StringBuffer();
        is = con.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;
        while( (line = br.readLine()) != null) {
            buffer.append(line + "\r\n");
        }
        is.close();
        con.disconnect();
        return buffer.toString();
    }
    catch(Throwable t) {
        t.printStackTrace();
    }
    finally {
        try { is.close(); } catch(Throwable t) {}
        try { con.disconnect(); } catch(Throwable t) {}
    }
    return null;
}

// Recherche de la météo par coordonées GPS
public String getWeatherByCoord(double lat, double lon) {
    HttpURLConnection con = null;
    InputStream is = null;
    try {
        con = (HttpURLConnection) ( new URL(API_URL + "?lat=" + String.valueOf(lat) + "&lon=" + String.valueOf(lon) + "&appid=" + API_KEY)).openConnection();
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();
        StringBuffer buffer = new StringBuffer();
        is = con.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;
        while( (line = br.readLine()) != null) {
            buffer.append(line + "\r\n");
        }
        is.close();
        con.disconnect();
        return buffer.toString();
    }
    catch(Throwable t) {
        t.printStackTrace();
    }
    finally {
        try { is.close(); } catch(Throwable t) {}
        try { con.disconnect(); } catch(Throwable t) {}
    }
    return null;
}

}

And, I call my API on the MainActivity:

package com.example.monlouis.myapplication;

import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

EditText mContenuText;
Button valider;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button bouton = (Button) findViewById(R.id.ValideButton);
    valider = (Button) findViewById(R.id.ValideButton);

    mContenuText = (EditText)findViewById(R.id.editText);

    valider.setOnClickListener(this);
    //System.out.println(strDate);
}


public void onClick(View v)
{
    // TODO Auto-generated method stub
    String chaine = mContenuText.getText().toString();
    Log.v("Essai",chaine);
    String infoAPI = WeatherAPI.getWeatherByCityName(chaine, "fr");
    System.out.println(infoAPI);
    ((TextView)findViewById(R.id.textView3)).setText("Ville: " + chaine);

    Calendar cal = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MMMM/d/E", Locale.FRANCE); // Set your locale!
    String strDate = sdf.format(cal.getTime());
    System.out.println(strDate);
}
}

I add the permission in the AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.monlouis.myapplication">

<uses-permission android:name="android.permission.INTERNET"/>
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

But I have this error when I want execute the app on my smartphone (console):

03-18 15:07:14.093 27210-27210/com.example.monlouis.myapplication I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
03-18 15:07:14.093 27210-27210/com.example.monlouis.myapplication I/System.out: (HTTPLog)-Static: isShipBuild true
03-18 15:07:14.093 27210-27210/com.example.monlouis.myapplication I/System.out: (HTTPLog)-Thread-1-982556185: SmartBonding Enabling is false, SHIP_BUILD is true, log to file is false, DBG is false
03-18 15:07:14.093 27210-27210/com.example.monlouis.myapplication I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
03-18 15:07:14.103 27210-27210/com.example.monlouis.myapplication W/System.err: android.os.NetworkOnMainThreadException
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at java.net.InetAddress.lookupHostByName(InetAddress.java:418)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at java.net.InetAddress.getAllByName(InetAddress.java:215)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.HostResolver$1.getAllByName(HostResolver.java:29)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:232)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:124)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:367)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:295)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:106)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.example.monlouis.myapplication.WeatherAPI.getWeatherByCityName(WeatherAPI.java:75)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.example.monlouis.myapplication.MainActivity.onClick(MainActivity.java:46)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.view.View.performClick(View.java:5197)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.view.View$PerformClick.run(View.java:20926)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.os.Handler.handleCallback(Handler.java:739)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:95)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.os.Looper.loop(Looper.java:145)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5951)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
03-18 15:07:14.113 27210-27210/com.example.monlouis.myapplication W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)

Why? Can you help me please?

Thanks!

Q. PICARD
  • 1
  • 1
  • A very simple way API for getting source code from a website is JSOUP. From what I understand this is what you would like to do – Janwilx72 Mar 18 '17 at 14:12
  • Use [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask.html) and put your code inside `doInBackground()` method as *This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.* – Iamat8 Mar 18 '17 at 14:19

2 Answers2

1

You need to call all methods in your WeatherAPI class OFF the UI thread...this is to ensure you are not blocking the UI thread (causing the UI to hang, or blocking the user).

There are a few different facilities built into Android to handle these things...look into AsyncTasks, or IntentServices.

General Docs: https://developer.android.com/guide/components/processes-and-threads.html

Booger
  • 18,579
  • 7
  • 55
  • 72
0

Never call Network operations on main thread use Loaders or Async task,these data intensive operations need to be handled by background thread.

OutOfBounds 94
  • 77
  • 1
  • 13