I'm building an application that retrieves data at a set interval from a website and I'm retrieving stale data. Specifically, I'm pulling scores from NFL games but whenever the score changes, my application alternates between returning the old score and the new score. Eventually, it will stabilize and only return the new score.
How do I prevent my application from returning stale data?
public class MainActivity extends Activity {
private String webSourceCode;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyAsyncTask().execute();
}
private class MyAsyncTask extends AsyncTask<Void, Void, List<Integer>> {
protected List<Integer> doInBackground(Void... params) {
StringBuilder sb = new StringBuilder();
try {
URL nfl = new URL("http://www.cbssports.com/nfl/scoreboard");
BufferedReader in = new BufferedReader(
new InputStreamReader(
nfl.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine);
}
in.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
webSourceCode = sb.toString();
return parseScores(webSourceCode);
}
protected void onPostExecute(List<Integer> listScores) {
updateViews(listScores);
//recursion
new MyAsyncTask().execute();
}
}
}
GET calls can be cached by server or intermediaries. You can pass a dynamic query parameters to ensure that the intermediary/server does not send back a cached response. Something like this will work:
URL nfl = new URL("http://www.cbssports.com/nfl/scoreboard?nocache="+new Date().getTime());
Related
I'm writing a android trivia app that uses the Open Trivia DB to generate its questions. The problem I'm incurring is that I'm simply unable to connect to the generated API url and I'm not sure why.
I'm simply trying to pull the raw text from the URL and then sort it later, here is the relevant code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start = (Button)findViewById(R.id.button);
try {
getJSON();
}
catch (IOException e){
Log.d("CREATION","Something wrong");
}
}
private String getJSON()throws IOException{
URL trivia = new URL("https://opentdb.com/api.php?amount=10");
URLConnection yc = trivia.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
Log.d("CREATION",inputLine);
in.close();
return "";
}
}
The Stack trace from the errors I get comes back with this:
at edu.niu.students.z1802067.triviaapp.MainActivity.getJSON(MainActivity.java:59)
which is this line of code:
yc.getInputStream()));
How could I write this to simply get all the raw text from the JSON?
First of all you try make request with UI thread. It's blocking UI for a long time (time of request)
Try use thread like this:
new Thread(){
#Override
public void run() {
try {
getJSON();
}
catch (IOException e){
Log.d("CREATION","Something wrong: " + e, e);
}
}
}.start();
Better solution for reading data form API is use library like https://square.github.io/retrofit/
It simplifies the task and data processing
Its taking too long to compile the code (around 5mins +, only for this app).
Also when it's finally done, complete HTML is not displayed in the logcat! Only partial.
Can you guys please point out what's wrong with the code?
Is it because of "InputStream" reading character by character (as the HTML is huge)?
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
String result = null;
try {
result = task.execute("http://www.amazon.com").get();
} catch (Exception e) {
e.printStackTrace();
}
Log.i("Result",result);
}
Yes. The more system calls you make like that, the worse your performance. You should be reading in multiple kilobytes at a time, not characters. If you need to loop over it one at a time, do that afterwards.
Also, use a StringBuilder!!!! + on a string is HIGHLY inefficient. For every character you make a new String object. StringBuilder avoids that.
I checked across StackOverflow for answers, but I did not find much. So, I am doing this for practice, like Hello World for working with JSON, I am getting JSON response from openweather API.
I write the name of the city in EditText and press the button to search for it and display JSON string in the logs.
public class MainActivity extends AppCompatActivity {
EditText city;
public void getData(View view){
String result;
String cityName = city.getText().toString();
getWeather weather = new getWeather();
try {
result = weather.execute(cityName).get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public class getWeather extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... urls) {
URL url;
HttpURLConnection connection = null;
String result = "";
try {
String finalString = urls[0];
finalString = finalString.replace(" ", "%20");
String fullString = "http://api.openweathermap.org/data/2.5/forecast?q=" + finalString + "&appid=a18dc34257af3b9ce5b2347bb187f0fd";
url = new URL(fullString);
connection = (HttpURLConnection) url.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while(data != -1){
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
city = (EditText) findViewById(R.id.editText);
}
}
What can I do to not get that message?
weather.execute(cityName).get()
When you do get() you are waiting the AsyncTask to finish. Thus you are running all heavy operation on Ui thread.
From documentation of get():
Waits if necessary for the computation to complete, and then retrieves its result.
Remove get().
I was being a bit naive, thinking I can read webpages the same way as you do in Java, but apparently you need to use threads or AsyncTask. Which I have no prior experience in and are proving to be hassle.
I've read http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html (3. point) which I semi understand but when I try to implement into my problem it all falls apart.
Here's my problem:
I need to read from an URL, it's a RSS feed.
Parse it all together
Insert it into ListView (arrayadapter)
This is my AsyncTask class, that I tried to recreate. I just want it to return a buffered reader, or the whole page but it's always null.
private class DownloadWebPageTask extends AsyncTask<String, Void, BufferedReader> {
#Override
protected BufferedReader doInBackground(String... urls) {
BufferedReader bs;
URL url = null;
try {
url = new URL(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
bs = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
return bs;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(BufferedReader result) {
br = result;
}
}
public RSS() throws IOException, ExecutionException, InterruptedException {
DownloadWebPageTask dl = new DownloadWebPageTask();
dl.execute(new String[] {"http://www.promet.si/dc/PROMET.ROADEVENTS.PP.RSS.SL"});
}
I'm sorry if this is a stupid question, but I don't fully understand posts explaining this and I have to solve this problem. I just need the page's content in any way shape or form. (Can be a String, BufferedReader)
#Override
protected String doInBackground(String... urls) throws IOException {
URLConnection connection = new URL(urls[0]).openConnection();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),"UTF-8");
StringBuilder stringBuilder = new StringBuilder();
String buffer;
while ((buffer = bufferedReader.readLine()) != null) {
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
Use the buffered reader to read line by line in the background thread, and make it return string.
I'm creating an app where I need a function to get plain text from a website. I am able to get the text and print it out on my PC just fine, but when I try running it on an Android device, the app won't start.
I believe it has something to do with throwing an IOException. I've been reading that I am not supposed to do that because I don't define the interface. Is there a way to get around this? Android Studio won't compile my code if I don't throw the exception.
The function:
public String getText(String site) throws IOException {
// Make a URL to the web page
URL url = new URL(site);
// Get the input stream through URL Connection
URLConnection con = url.openConnection();
InputStream is =con.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// read each line and return the final text
String res = "";
String line = null;
while ((line = br.readLine()) != null) {
//System.out.println(line);
res += line;
}
return res;
}
And this is how Android Studio makes me run it in the onCreate method:
String text = null;
try {
text = getText("http://myWebsite.com");
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
First, read your logcat - you should see your exception there with full stacktrace. Second, there is nothing wrong with catching IOException, but you must do something with it once cached - like inform user of problem in functionality - like no more space, etc.
And this is how Android Studio makes me run it in the onCreate method:
this is a problem, because your are getting data from your site on UI thread, you must do it from worker thread, ie. AsyncTask.
You can not do it in the main thread
try this
class MyTask extends AsyncTask<Void, Void, String>{
private String site;
MyTask(String site) {
this.site = site;
}
#Override
protected String doInBackground(Void... params) {
try {
URL url = new URL(site);
URLConnection con = url.openConnection();
InputStream is =con.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// read each line and return the final text
String res = "";
String line = null;
while ((line = br.readLine()) != null) {
//System.out.println(line);
res += line;
}
return res;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s != null){
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
}
}
}
where to get a string is used as
new MyTask("http://myWebsite.com").execute()