Sometime networkonmainthreadexception in AsyncTask - android

I am getting NetworkonMainThreadException sometime.I dont know what is the problem. First time it opens with no error, But after few times closing and opening cause the NetworkOnMainThreadException.
Below is my MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadWebpageTask().execute();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
List<Member> members = new ArrayList<Member>();
ListView listView = (ListView) findViewById(R.id.listView1);
String ss = "";
InputStream is;
HttpURLConnection connection ;
#Override
protected String doInBackground(String... urls) {
try {
URL url = new URL("http://192.168.1.107:8080/SEWS_webservice/rest/members");
connection = (HttpURLConnection) url.openConnection();
is = connection.getInputStream();
} catch (IOException e) {
System.out.println(e+"***********************&&&&&&&&&&&&&");
}finally {
connection.disconnect();
}
return ss;
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
XmlPullParserHandler parser = new XmlPullParserHandler();
parser.parse(is);
members = parser.getMembers();
ArrayAdapter<Member> adapter = new ArrayAdapter<Member>(getApplicationContext(),android.R.layout.simple_list_item_1, members);
listView.setAdapter(adapter);
}
}
}
This is XMLPullParser handler
public class XmlPullParserHandler {
private List<Member> members= new ArrayList<Member>();
private Member member;
private String text;
public List<Member> getMembers() {
return members;
}
public List<Member> parse(InputStream is) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
parser.setInput(is, null);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagname = parser.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if (tagname.equalsIgnoreCase("member")) {
// create a new instance of employee
member = new Member();
}
break;
case XmlPullParser.TEXT:
text = parser.getText();
break;
case XmlPullParser.END_TAG:
if (tagname.equalsIgnoreCase("member")) {
// add employee object to list
members.add(member);
}else if (tagname.equalsIgnoreCase("memberId")) {
member.setMemberId(Integer.parseInt(text));
}
else if (tagname.equalsIgnoreCase("firstName")) {
member.setFirstName(text);
}
else if (tagname.equalsIgnoreCase("middleName")) {
member.setMiddleName(text);
}
else if (tagname.equalsIgnoreCase("lastName")) {
member.setLastName(text);
}
break;
default:
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return members;
}
}

The problem is even though you are connecting up to the website properly in the background you are reading from the underlying socket using the InputStream. You need to refactor your solution so that you are returning a String or raw data from your InputStream as the result of doInBackground and closing out any http connections. Something like
#Override
protected String doInBackground(String... urls) {
try {
URL url = new URL("http://192.168.1.107:8080/SEWS_webservice/rest/members");
connection = (HttpURLConnection) url.openConnection();
is = connection.getInputStream();
ByteArrayOutputStream oStream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int numRead = -1;
while ((numRead = (is.read(buffer))) > -1) {
oStream.write(buffer, 0, numRead);
}
return new String(oStream.getBytes(), "UTF-8");
} catch (IOException e) {
System.out.println(e+"***********************&&&&&&&&&&&&&");
}finally {
connection.disconnect();
}
return ss;
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
XmlPullParserHandler parser = new XmlPullParserHandler();
parser.parse(result);
members = parser.getMembers();
ArrayAdapter<Member> adapter = new ArrayAdapter<Member>(getApplicationContext(),android.R.layout.simple_list_item_1, members);
listView.setAdapter(adapter);
}
Should do it if the XmlPullParserHandler can read Strings, otherwise that too will need to get moved to the background portion.

Seems like XmlPullParser doesn't like to work on UI thread :)
I could not find exact proves of this, but even official example makes it work in AsyncTask.
In your case just try to move next lines:
XmlPullParserHandler parser = new XmlPullParserHandler();
parser.parse(is);
members = parser.getMembers();
into doInBackground() method and check the result.
PS. Not relating to question, but what is purpose of this String ss = "";?
You can change AsyncTask<String, Void, String> to AsyncTask<String, Void, Void> if you don't want to return anything.
Or, better way, - you can do this AsyncTask<String, Void, List<Member>>.
Then you make protected void onPostExecute(List<Member> result) and use this result in your Adapter code.

Related

Unit Testing Android Studio Textview

This is my main activity which gets a json array from a URL. My problem is that when I try and Unit test what should be in the textview it gives me a null pointer exeption.
public class MainActivity extends AppCompatActivity {
TextView txtJson;
ProgressDialog pd;
public static TextView testString;
String jsonString = null;
List<Location> locations;`enter code here`
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtJson = (TextView) findViewById(R.id.tvJsonItem);
testString = (TextView) findViewById(R.id.test_for_string);
new JsonTask().execute("https://wsu-dining-service.s3.amazonaws.com/current-menu.json");
}
protected void postCreate()
{
mapStrinToClass();
testString.setText(locations.get(0).getName());
}
private void mapStrinToClass()
{
ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = objectMapper.getFactory();
try {
JsonParser jsonParser = jsonFactory.createParser(jsonString);
locations = objectMapper.readValue(jsonString,
new TypeReference<List<Location>>() {
});
} catch (IOException e) {
e.printStackTrace();
}
}
private class JsonTask extends AsyncTask<String, String, String> {
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(MainActivity.this);
pd.setMessage("Please wait");
pd.setCancelable(false);
pd.show();
}
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line+"\n");
Log.d("Response: ", "> " + line); //here u ll get whole response...... :-)
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (pd.isShowing()){
pd.dismiss();
}
jsonString = result;
postCreate();
}
}
}
My unit test
* When I run the app the textview is populated with "Tim & Jeanne's Dining Commons" but the test fails and says the testString.getText().toString(); is null
#Test
public void isMenuCorrect() {
String menuTxt = MainActivity.testString.getText().toString();
assert(menuTxt == "Tim & Jeanne's Dining Commons");
}
First of all, you should use Espresso to run UI tests, under the androidTest folder. Example:
onView(allOf(withId(R.id.tvJsonItem), withText("Tim & Jeanne's Dining Commons")).check(matches(isDisplayed()));
Basically what we're doing here is checking if a view with id R.id.tvJsonItem and with a text "Tim & Jeanne's Dining Commons" is displayed on the screen. Now how to run Espresso tests is not in this question's scope.
Second, your production code should never know what's going on in the tests, like you have created a TextView just to be used in your unit tests.
Finally, never have static references to your views since you can't guarantee your activity has been created by the time you try to access them. In fact, a view should only be seen by its parent. In your case, the reference TextView should be private in your activity.

ArrayAdapter is null even after getting a string array as a parameter

I'm working on the Sunshine app in the Developing Android App course by Udacity. Currently stuck in lesson 2. I've listed down the MainActivity.java that contains a listview that is populated by a network call in the AsyncTask as an inner class in the MainActivity.java. But the application crashes, due to a null pointer exception, as the array adapter is null. I've tried debugging, and the weekForecast (i.e., the ArrayList that stores the parsed data, and is a parameter to the creation of the ArrayAdapter) does have valid parsed data. Thanks for the help in advance.
public class MainActivity extends AppCompatActivity {
ListView listView;
ArrayAdapter<String> arrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=(ListView)findViewById(R.id.listview_forecast);
GettingWeatherFromNetwork gettingWeatherFromNetwork = new GettingWeatherFromNetwork();
gettingWeatherFromNetwork.execute("94043");
listView.setAdapter(arrayAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main,menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case R.id.action_settings : return true;
case R.id.action_refresh : GettingWeatherFromNetwork gettingWeatherFromNetwork = new GettingWeatherFromNetwork();
gettingWeatherFromNetwork.execute("94043");
return true;
}
return super.onOptionsItemSelected(item);
}
public class GettingWeatherFromNetwork extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = GettingWeatherFromNetwork.class.getSimpleName();
//Removed API KEY. But it is a part of the main code I'm running.
private final String API_KEY = " ";
#Override
protected String[] doInBackground(String... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String forecastJsonStr = null;
String format = "json";
String units = "metric";
int noOfDays = 7;
try {
final String BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String MODE_PARAM = "mode";
final String UNITS_PARAM = "units";
final String COUNT_PARAM = "cnt";
final String KEY_PARAM = "appid";
Uri builtURI = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM,params[0])
.appendQueryParameter(MODE_PARAM,format)
.appendQueryParameter(UNITS_PARAM,units)
.appendQueryParameter(COUNT_PARAM, String.valueOf(noOfDays))
.appendQueryParameter(KEY_PARAM,API_KEY)
.build();
String Url = builtURI.toString();
URL url = new URL(Url);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e(LOG_TAG, String.valueOf(e));
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, String.valueOf(e));
}
}
}
String [] weatherForecast = new String[0];
WeatherParser weatherParser = new WeatherParser();
try {
weatherForecast = weatherParser.getWeatherDataFromJson(forecastJsonStr,7);
} catch (JSONException e) {
e.printStackTrace();
}
return weatherForecast;
}
#Override
protected void onPostExecute(String[] s) {
List<String> weekForecast = new ArrayList<String>(Arrays.asList(s));
arrayAdapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.list_item_forecast,R.id.list_item_forecast_textview,weekForecast);
}
}
}
Try removing the line
listView.setAdapter(arrayAdapter);
from onCreate method and add it in onPostExecute() method of AsyncTask, after initialising the arrayAdapter.
#Override
protected void onPostExecute(String[] s) {
List<String> weekForecast = new ArrayList<String>(Arrays.asList(s));
arrayAdapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.list_item_forecast,R.id.list_item_forecast_textview,weekForecast);
//set adapter set to listview after initialzing it.
listView.setAdapter(arrayAdapter);
}

JSoup parsed elements empty

I am trying to parse some data using JSoup, this is all happening in a asynctask (doInBackground) part of my MainActivity.
Unfortunately all the elements (9) are empty when I execute the app.
When I debug below codeline, I actually get the complete website, it`s all there.
The method readMultipleLinesRespone() is located in another class HttpUtility where I also call my Post and Get requests.
I tested this upfront by saving the website as a file and using JSoups assets ability, it worked perfectly then.
The setupAdapter() method in onPostExecute fills a ExpandableListview with data, should this info be nessecary. If you need more info pls ask.
Can somebody assist and tell me what I am doing wrong?
response1 = util.readMultipleLinesRespone(); <--- debugged and all data (seems) to be there but isn`t.
Edit: If I print response1, there is indeed no data to parse.
Logcat output:
E/Resonse:: [Ljava.lang.String;#3d3410a
Below is the method readMultipleLinesRespone from HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
InputStream inputStream = null;
if (httpConn != null) {
inputStream = httpConn.getInputStream();
} else {
throw new IOException("Connection is not established.");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
inputStream));
List<String> response = new ArrayList<String>();
String line = "";
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
return (String[]) response.toArray(new String[0]);
}
The asynctask where it`s all hapening:
private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
this.mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage("Laden...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest("https://mobile.somesite.nl/Data", null);
response1 = util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (response1.length > 0) {
Document doc = Jsoup.parse(response1.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
if (els.size() > 0) {
fac_naam = els.get(0).text();
fac_straat = els.get(1).text();
fac_post = els.get(2).text();
con_tel = els.get(3).text();
con_email = els.get(4).text();
betaal_reknr = els.get(5).text();
betaal_houd = els.get(6).text();
zig_gebruiker = els.get(7).text();
zig_wacht = els.get(8).text();
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPreExecute();
setupAdapter();
mProgressDialog.dismiss();
}
}
In the meantime I solved the problem.
I did not pass the response string correctly to the asynctask which parses the required elements.
Just required a public string in which the response is being set and passed (not an elegant way but it works):
public static String HttpResponse = "";
In the HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
...
TabFragment1.HttpResponse = response.toString();
...
return (String[]) response.toArray(new String[0]);
}
Then pass it to the asynctask:
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest(LoginActivity.PersData_URL, null);
util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (HttpResponse.length() > 0) {
Document doc = Jsoup.parse(HttpResponse.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
...
}
return null;
}

Fill Listview from XML obtained from HTTP POST

I'm trying to populate a ListView with the data obtained using HTTP POST URL, the data received is a XML document like this:
<?xml version="1.0" encoding="utf-8" ?>
- <Arrives>
- <Arrive>
<IdStop>226</IdStop>
<idLine>70</idLine>
<IsHead>True</IsHead>
<Destination>ALSACIA</Destination>
<IdBus>0000</IdBus>
<TimeLeftBus>0</TimeLeftBus>
<DistanceBus>373</DistanceBus>
<PositionXBus>-1</PositionXBus>
<PositionYBus>-1</PositionYBus>
<PositionTypeBus>2</PositionTypeBus>
</Arrive>
- <Arrive>
<IdStop>226</IdStop>
<idLine>11</idLine>
<IsHead>True</IsHead>
<Destination>BARRIO BLANCO</Destination>
<IdBus>0000</IdBus>
<TimeLeftBus>161</TimeLeftBus>
<DistanceBus>1498</DistanceBus>
<PositionXBus>-1</PositionXBus>
<PositionYBus>-1</PositionYBus>
<PositionTypeBus>1</PositionTypeBus>
</Arrive>
- <Arrive>
<IdStop>226</IdStop>
<idLine>N3</idLine>
<IsHead>True</IsHead>
<Destination>CIBELES</Destination>
<IdBus>0000</IdBus>
<TimeLeftBus>422</TimeLeftBus>
<DistanceBus>1923</DistanceBus>
<PositionXBus>-1</PositionXBus>
<PositionYBus>-1</PositionYBus>
<PositionTypeBus>1</PositionTypeBus>
</Arrive>
</Arrives>
The only tags which I need to use in ListView are idLine, Destination and TimeLeftBus.
The method I planned to use in HTTP Request: (I can do this using GET METHOD too)
public void postData() {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("SITE URL");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("apiid", "API ID"));
nameValuePairs.add(new BasicNameValuePair("apikey", "API KEY"));
nameValuePairs.add(new BasicNameValuePair("stopid", "STOP ID"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Log exception
} catch (IOException e) {
// TODO Log exception
}
}
How can implement this? Thanks for your help.
I'm not really familiar with obtaining data from an HTTP POST URL but I do know how to get your xml data to your list view. What I would do is
Create an object to encapsulate idLine, Destination and TimeLeftBus
Use an xml parser to return a list of those objects
Create a custom adapter (if necessary) to populate your list view.
See the code below for each of these steps.
Step 1:
public class ArrivalInfo {
private String idLine;
private String destination;
private String timeLeft;
public void setIdLine(String id) {
this.idLine = id;
}
public String getIdLine() {
return idLine;
}
...(getters and setters for other fields)
}
Step 2:
public class XMLParser {
//the tags as found in your XML document
private static final String ARRIVE = "arrive";
private static final String ID_LINE = "idLine";
private static final String DEST = "Destination";
private static final String TIME_LEFT_BUS = "TimeLeftBus";
private ArrivalInfo curArrival = null;
List<ArrivalInfo> arrivals = new ArrayList<ArrivalInfo>();
public List<ArrivalInfo> getArrivals() {
return arrivals;
}
public void parseXml() {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
InputStream stream = getResources().openRawResource(...) (this can be done in different
ways depending on where the file is)
int eventType = xpp.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) {
handleStartTag(xpp.getName());
}
else if (eventType == XmlPullParser.END_TAG) {
handleEndTag(xpp.getName());
}
else if (eventType == XmlPullParser.TEXT) {
handleText(xpp.getName(), xpp.getText());
}
eventType = xpp.next();
} catch(NotFoundException e) {
...handle exeptions
}
public void handleStartTag(String tag) {
if(tag.equalsIgnoreCase(ARRIVE)) {
curArrival = new ArrivalInfo();
}
}
public void handleEndTag(String tag) {
if(tag.equalsIgnoreCase(ARRIVE)) {
arrivals.add(curArrival);
}
}
public void handleText(String tag, String text) {
if(curArrival != null) {
if(tag.equalsIgnoreCase(ID_LINE)) {
curArrival.setIdLine(text);
}
else if (tag.equalsIgnoreCase(DEST)) {
curArrival.setDestination(text);
}
// and so on...
}
}
} //end of XmlParser
Step 3: (This would happen in a non UI thread, i.e. use an AsyncTask to do this on a different thread);
public class MyActivity extends Activity {
private ListView mListView;
private StableArrayAdapter adapter;
private List<ArrivalInfo> arrivals;
private class LoadDataTask extends AsyncTask<Void, Void, List<ArrivalInfo>>() {
#Override
public void doInBackground(Void...params) {
XmlParser parser = new XmlParser();
try {
parser.parseXml();
} finally {
return parser.getArrivals();
}
}
#Override
public void onPostExecute(List<ArrivalInfo> list) {
if(mListView != null && adapter != null) {
arrivals = list;
adapter.notifyDataSetChanged();
}
}
} // end of loading task.
#Override
public void onCreate(Bundle savedInstanceState) {
arrivals = new ArrayList<ArrivalInfo>();
setContentView(R.layout.my_layout);
mListView = findViewById(android.R.id.list);
StableArrayAdapter adapter = new StableArrayAdapter(this,
android.R.layout.simple_list_item_1, arrivals);
mListView.setAdapter(adapter);
new LoadDataTask().execute();
}
} // end of your activity
And that's pretty much it! hope that helps you do what you want to do.

Android call to webservice returns no result although the URL works fine

This the most bizarre problem I have ever seen. I get "No product available" although there are products in my database.
Here my service:
public class AllProductsService {
private String URL = "xxxx";
Gson gson;
public AllProductsService(int page) {
gson = new Gson();
URL = URL + "?page=" + Integer.toString(page);
}
private InputStream sendRequest(URL url) throws Exception {
try {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
return urlConnection.getInputStream();
}
} catch (Exception e) {
throw new Exception("");
}
return null;
}
public List<Product> getProducts() {
try {
InputStream inputStream = sendRequest(new URL(URL));
if(inputStream != null) {
InputStreamReader reader = new InputStreamReader(inputStream);
return gson.fromJson(reader, new TypeToken<List<Product>>(){}.getType());
}
}
catch (Exception e) {
}
return null;
}
}
And my AsyncTask class:
private class AllProductsTask extends AsyncTask<Void, Void, List<Product>> {
#Override
protected void onPreExecute() {
setSupportProgressBarIndeterminateVisibility(true);
}
#Override
protected List<Product> doInBackground(Void... params) {
AllProductsService allProductsService = new AllProductsService(current_page);
List<Product> liste = allProductsService.getProducts();
if (liste != null && liste.size() >= 1)
return liste;
return new ArrayList<Product>();
}
protected void onPostExecute(java.util.List<Product> result) {
setSupportProgressBarIndeterminateVisibility(false);
if (result.isEmpty() && isInternetPresent && current_page < 2) {
Crouton.makeText(MainActivity.this, "No product available!", Style.ALERT).show();
}
//populate adapter
}
}
When I call the URL from the browser, results are displayed correctly. I also try with a different URL with the same code and it works fine. I don't know why.
I think problem is; you are returning the
new ArrayList<Product>();
in doInBackground() of Asynctask which is null. You should return the liste here. or place the return new ArrayList<Product>(); in else condition
I found the solution: just have to remove the slash at the end of the URL. Thank you #trevor-e. Knowing the HTTP code status help me.

Categories

Resources