I am having an issue, when I try to update some information in the background in my app I constantly get reports of ANR (Are not responding).
The code block is as follows
class getServerTime extends AsyncTask<String, Long, Long> {
private Long getInternetData() {
String sURL = "http://crystalmathlabs.com/tracker/api.php?type=time"; //just a string
// Connect to the URL using java's native library
HttpURLConnection connect = null;
try {
int responseCode = -1;
List<String> listSet = new ArrayList();
URL url = new URL(sURL);
connect = (HttpURLConnection) url.openConnection();
connect.setConnectTimeout(R.integer.timeoutLengthWithACapitalT);
connect.setReadTimeout(R.integer.timeoutLengthWithACapitalT);
connect.connect(); //this is the timeout line
responseCode = connect.getResponseCode();
if (responseCode < 400) {
BufferedReader in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
listSet.add(inputLine);
in.close();
if (listSet.get(0) != null)
return Long.parseLong(listSet.get(0));
}
return -1L;
}
catch (java.io.FileNotFoundException e) {
Log.e("getServerTime", "File Not Found: " + e.getMessage());
} catch (Exception e) {
Log.e("getServerTime", "Unknown Exception " + e.getMessage());
}
finally{
if (connect != null)
connect.disconnect();
}
return -1L;
}
#Override
protected Long doInBackground(String[] params) {
Long response;
new Scores();
try {
response = getInternetData();
if (response != null) {
return response;
}
return -1L;
} catch (Exception e) {
Log.d("Error in getServerTime", "" + Log.getStackTraceString(e.getCause().getCause()));
}
return -1L;
}
}
On connect.connect I receive timeouts.
Attached below are two examples of the ANR reports, I simply can't figure this out, please help!
https://pastebin.com/F7iZ267D
https://pastebin.com/W1eSdH4F
at android.os.AsyncTask.get (AsyncTask.java:507)
at
com.yargonauts.burk.runescapemarketwatch.crystalMathLabs.a.a
(crystalMathFunctions.java:30)
You are calling AsyncTask.get(), this pretty much negates the use of an asynctask since it blocks the thread until the async task is done.
This blocking causes the ANR since the main thread is stuck waiting for the result.
You need to override the onPostExecute(Result) method and perform the follow-up work there. Check out the Usage section of the asynctask javadoc: https://developer.android.com/reference/android/os/AsyncTask.html
Related
On the phone string is empty, why thats happend?
Phone is android version 10, nox is 4.4.3 if thats matters?
I try more codes for read web page but result is same, i dont know why its happend?
class GetData extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
HttpURLConnection urlConnection = null;
String result = "";
try {
URL url = new URL("http://www.b92.net/info/rss/sport.xml");
urlConnection = (HttpURLConnection) url.openConnection();
int code = urlConnection.getResponseCode();
if(code==200){
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
if (in != null) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = bufferedReader.readLine()) != null)
result += line;
}
in.close();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
urlConnection.disconnect();
}
return result;
}
#Override
protected void onPostExecute(String result) {
tv.setText(result);
}
}
}
To turn #intellij-amiya s comment into an answer:
Use https instead of http: https://www.b92.net/info/rss/sport.xml
this blog post tells us that clear-traffic is (basically) forbidden now (as #morrison-chang pointed out)
You need to add Internet Permission in Manifest.
I have external class extending AsyncTask to get string from website to parse it as JSONObject or JSONArray. Currently i am using method .get() to get the result, but app is dropping frames, while waiting for server to respond. I want to use it reusable because I am getting data from many different classes.
My Asynctask class:
public class JsonTask extends AsyncTask<String, String, String> {
protected String doInBackground(String...params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
Log.d("Response: ", "> Establishing Connection" );
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);
}
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;
}}
Now i am getting data by simply:
String result = new JsonTask().execute(url).get();
As per documentation for the get method:
Waits if necessary for the computation to complete, and then retrieves its result.
Therefore it will block the UI until it finishes the background task which will return the result.
You can create a listener that accepts the return value of the doInBackground in your JsonTask which the onPostExecute will call the listener.
I think you can read document again .
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
I have got problem with read output form request.
public JSONArray listLights()
{
try
{
URL adres = new URL("https://api.lifx.com/v1/lights/all");
HttpURLConnection polaczenie = (HttpURLConnection) adres.openConnection();
polaczenie.setRequestProperty("Authorization", "Bearer " + apiKey);
polaczenie.setRequestMethod("GET");
BufferedReader wejscie = new BufferedReader(new InputStreamReader((polaczenie.getInputStream())));
StringBuilder odpowiedz = new StringBuilder();
String json;
while ((json = wejscie.readLine()) != null)
odpowiedz.append(json);
wejscie.close();
return new JSONArray(odpowiedz.toString());
}
catch (Exception wyjatek)
{
wyjatek.printStackTrace();
}
return new JSONArray();
}
StackTrace
I added to AndroidManifest Internet access too.
Welcome to leave any comments. :P
EDIT:
I google internet and found partial solution. Added AsyncTask, but now I'm receiving '429' response code.
public class JSONTask extends AsyncTask<String, String, String>
{
String apiKey = "blah_blah_blah";
String txtresult;
#Override
protected String doInBackground(String... params) {
HttpsURLConnection connection = null;
BufferedReader reader = null;
try
{
URL adres = new URL(params[0]);
HttpsURLConnection polaczenie = (HttpsURLConnection) adres.openConnection();
polaczenie.setRequestProperty("Authorization", "Bearer " + apiKey);
polaczenie.setRequestMethod("GET");
System.out.println(polaczenie.getResponseCode());
InputStream stream = polaczenie.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null)
{
buffer.append(line);
}
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 s)
{
super.onPostExecute(s);
widok.setText(s);
}
}
My current StackTrace
EDIT2:
New day, new surprise. I figure out that I'm making connection with Bulb once/twice on every 10 attempts. Any ideas?
HTTP Status code 429 means too many requests in a given an amount of time. So how many requests exactly are you doing?
android.os.NetworkOnMainThreadException it means, that You have to make a htttp request from another threat than UIthread. Why are you using async task ?
Edit: You can also try make a call from postman and maybe You will see the problem.
In the end, everything is working. Problem was on the side of bulb or Lifx Cloud.
I'm trying to learn Android development by creating the movies app from the Google Udacity course. In my code below upon executing urlConnection.connect(), the code automatically goes to the finally block without any errors/exceptions.
Can you please help me see what's wrong with my code? Thanks!
public class FetchMoviesTask extends AsyncTask<Void, Void, String> {
private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();
protected String doInBackground(Void... params) {
String JSONResponse = null;
//These are declared outside as they'll be used in both try and finally blocks
BufferedReader reader = null;
HttpURLConnection urlConnection = null;
try {
//construct your URL from a URI
Uri.Builder URIbuilder = new Uri.Builder();
URIbuilder.scheme("http")
.authority("api.themoviedb.org")
.appendPath("3")
.appendPath("movie")
.appendPath("popular")
.appendQueryParameter("api_key", BuildConfig.TMDB_API_KEY);
//instantiate URL
URL popularURL = new URL(URIbuilder.toString());
Log.v(LOG_TAG, "Built URL: " + popularURL.toString());
//create and open HTTP connection
urlConnection = (HttpURLConnection) popularURL.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
//InputStream is needed to read the response
//http://developer.android.com/reference/java/net/HttpURLConnection.html
InputStream inputStream = urlConnection.getInputStream();
if (inputStream == null) {
Log.e(LOG_TAG, "Null input stream");
return null; //no data returned from HTTP request
}
//!!want to see what InputStream looks like
Log.v(LOG_TAG, "inputStream.toString(): " + inputStream.toString());
//BufferedReader is used to wrap a Reader and buffer its input
//to read InputStream, a "reader" is required and that's InputStreamReader (duh)
//http://developer.android.com/reference/java/io/BufferedReader.html
reader = new BufferedReader(new InputStreamReader(inputStream));
//!!want to see what BufferedReader looks like
Log.v(LOG_TAG, "reader.toString(): " + reader.toString());
//replaced StringBuffer w/ StringBuilder. will it work?
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
builder.append(line + "\n");
}
if (builder.length() == 0) return null; //empty stream. no point in parsing
JSONResponse = builder.toString();
Log.v(LOG_TAG, "JSON Response: " + JSONResponse);
return parseJSON(JSONResponse);
} catch (IOException e) {
Log.e(LOG_TAG, "Error", e);
return null;
} catch (JSONException e) {
Log.e(LOG_TAG, "Error parsing JSON", e);
return null;
} catch (Error e) {
Log.e(LOG_TAG, "Unknown error", e);
} finally {
if (urlConnection != null) urlConnection.disconnect();
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
//will only be triggered if there's an error getting/parsing data
return null;
}
}
CommonsWare pointed me to the possible cause of the issue, which was a missing INTERNET permission. Adding it solved my problem. Thanks for all the responses!
The problem is this comment in your code:
//will only be triggered if there's an error getting/parsing data
That's false.
The return in the try block won't be ignored if a finally block is defined, only if that finally block also includes a return.
In other words, if you have "return" in both try and finally, the one inside finally is the one which gets executed.
Source: Java try-finally return design question
Edit:
You may want to check this out: Does finally always execute in Java?
I am working on an android app, and am running into some troubles with registering users. I want to post a JSON object to my server and receive one back. I can successfully create a JSON object with the right information but when I go to post it I get a NetworkOnMainThreadException or my HttpClient class returns null when it should be returning a JSONObject and I am very confident that my web server works correctly. I understand that you cannot connect to the network on the main thread and have created an HttpClient class that uses AsnycTask (although probably not correctly). I have been working on this for quite a while and would appreciate any guidance in the right direction.
//Main activity
#Override
public void onClick(View arg0) {
if(!(isEmpty(name) || isEmpty(username) || isEmpty(password) || isEmpty(email))) {
user = new JSONObject();
try {
user.put("username", username.getText().toString());
user.put("name", name.getText().toString());
user.put("email", email.getText().toString());
user.put("password", password.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
jRegister = new JSONObject();
try {
jRegister.put("apiToken", Utilities.apiToken);
jRegister.put("user", user);
Log.i("MainActivity", jRegister.toString(2));
} catch (JSONException e) {
e.printStackTrace();
}
//
HttpClient client = new HttpClient(url, jRegister);
result = client.getJSONFromUrl();
try {
if(result != null)
tv.setText(result.toString(2));
else
tv.setText("null");
} catch (JSONException e) {
e.printStackTrace();
}
}else {
tv.setText("");
}
}
HttpClient Class
public class HttpClient extends AsyncTask<Void, Void, JSONObject>{
private final String TAG = "HttpClient";
private String URL;
private JSONObject jsonObjSend;
private JSONObject result = null;
public HttpClient(String URL, JSONObject jsonObjSend) {
this.URL = URL;
this.jsonObjSend = jsonObjSend;
}
public JSONObject getJSONFromUrl() {
this.execute();
return result;
}
#Override
protected JSONObject doInBackground(Void... params) {
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPostRequest = new HttpPost(URL);
StringEntity se;
se = new StringEntity(jsonObjSend.toString());
// Set HTTP parameters
httpPostRequest.setEntity(se);
httpPostRequest.setHeader("Accept", "application/json");
httpPostRequest.setHeader("Content-type", "application/json");
long t = System.currentTimeMillis();
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
Log.i(TAG, "HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read the content stream
InputStream instream = entity.getContent();
// convert content stream to a String
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
JSONObject jsonObjRecv = new JSONObject(resultString);
// Raw DEBUG output of our received JSON object:
Log.i(TAG,"<JSONObject>\n"+jsonObjRecv.toString()+"\n</JSONObject>");
return jsonObjRecv;
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(JSONObject jObject) {
result = jObject;
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
I understand that you cannot connect to the network on the main thread
and have created an HttpClient class that uses AsnycTask (although
probably not correctly).
You are right you have not implemented it the right way.
In your onClick events (still on Main thread) you performed a network activity causing the error:
HttpClient client = new HttpClient(url, jRegister);
result = client.getJSONFromUrl();
Instead you should run the network operation inside of the AsnycTask
public class GetJsonTask extends AsyncTask<Void, Void, JSONObject >{
private String URL;
private JSONObject jsonObjSend;
public GetJsonTask(String URL, JSONObject jsonObjSend) {
this.URL = URL;
this.jsonObjSend = jsonObjSend;
}
#Override
protected JSONObject doInBackground(Void... params) {
JSONObject jsonObjRecv;
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPostRequest = new HttpPost(URL);
StringEntity se;
se = new StringEntity(jsonObjSend.toString());
// Set HTTP parameters
httpPostRequest.setEntity(se);
httpPostRequest.setHeader("Accept", "application/json");
httpPostRequest.setHeader("Content-type", "application/json");
long t = System.currentTimeMillis();
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
Log.i(TAG, "HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read the content stream
InputStream instream = entity.getContent();
// convert content stream to a String
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
jsonObjRecv = new JSONObject(resultString);
// Raw DEBUG output of our received JSON object:
Log.i(TAG,"<JSONObject>\n"+jsonObjRecv.toString()+"\n</JSONObject>");
}
}
catch (Exception e) {
e.printStackTrace();
}
return jsonObjRecv;
}
protected void onPostExecute(JSONObject result) {
try {
if(result != null)
tv.setText(result.toString(2));
else
tv.setText("null");
} catch (JSONException e) {
e.printStackTrace();
}
}else {
tv.setText("");
}
}
}
Then you call your async in onclik method like this:
public void onClick(View arg0) {
//.......
GetJsonTask client = new GetJsonTask(url, jRegister);
client.execute();
}
One problem in your code is that your expectations of AsyncTask aren't quite right. In particular this function:
public JSONObject getJSONFromUrl() {
this.execute();
return result;
}
AsyncTask runs the code in the doInBackground() function in a separate thread. This means that once you call execute() you have two parallel lines of execution. You end up with what's called a Race Condition. When you reach the return result line, a couple of things can be happening:
doInBackground() hasn't run and therefore result is still has the default value. In this case null.
doInBackground() can be in the middle of the code. In your particular case because it doesn't modify result then this doesn't affect you much. But it could be on any line (or middle of a line sometimes if operations aren't atomic) when that return happens.
doInBackground() could've finished, but since onPostExecute() runs on the UI thread it has to wait until your onClick handler is finished. By the time onPostExecute() has a chance to run onClick already tried to update tv with whatever it was that getJSONFromUrl returned, most likely null.
The way to set up tasks with AsyncTask is to give it the information it needs to do it's work, start it up with execute, and since you can't know how long it will take to complete, let it handle the finishing steps of the task.
This means that after calling execute you don't wait around for it's result to update views (like in your case), but rather rely on the AsyncTask's onPostExecute or related methods to take over the next steps.
For your case this would mean that your onPostExecute should look something like:
protected void onPostExecute(JSONObject result) {
try {
if(result != null)
tv.setText(result.toString(2));
else
tv.setText("null");
} catch (JSONException e) {
e.printStackTrace();
}
}