This code works fine in 2.2 emulator (API 8), but it is not working in 4.1 emulator (API
16). Any idea?
Thank you for all your answers and interest
`try
{
String url = "http://10.0.2.2:8080/cofradeapps/static/hermandades.xml";
urlHermandades = new URL(url);
HttpURLConnection urlConnection = (HttpURLConnection) urlHermandades.openConnection();
InputStream in = urlConnection.getInputStream();
return in;
}
catch (IOException e)
{
throw new RuntimeException(e);
}
You can't do networking on the UI thread on newer versions of Android, you'll need to use another thread, most likely an ASyncTask.
private class YourClass extends AsyncTask<URL> {
protected String doInBackground(URL... urls) {
//Do your stuff here
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//When you're finished update the UI thread with your results
}
}
Related
I created a REST API which appears to work fine (I tested the GET request of interest using Postman).
I am working to make an identical request from an Android application using an AsyncTask. The hope is to assign a string value generated by the AsyncTask to a string variable in the Android activity.
I have used a Toast to view the string output of the doInBackground method, which is passed to the onPostExecute method of the AsyncTask, to make sure that the call to the API is working and it works fine.
The problem comes when I assign the string output of the AsyncTask to the string variable defined in the Activity class. After executing the AsyncTask I am using a Toast to view the value of the string variable and it is reflecting the assignment performed in the onPostExecute method.
I will now share the code that I am using in the hope that you can help me to find where I might be going wrong. After the button is clicked, I intend for the validate AsyncTask to execute and assign a value to emailValid.
In view of the code below, my question in the most direct way I can put it: "Why is Toast 2 displaying while Toast 1 is not?"
Thank you in advance for your assistance.
public class JoinActivity extends AppCompatActivity implements View.OnClickListener
{
EditText email_et;
Button join_b;
String emailValid;
#Override
protected void onCreate(Bundle savedInstance)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join);
emailValid = "No";
join_b = (Button) findViewById(R.id.aj_join_b);
join_b.setOnClickListener(this);
}
#Override
public void onClick(View view)
{
email_et = (EditText) findViewById(R.id.et_aj_email_address);
new JoinActivity.validate().execute(email_et.getText().toString());
// Toast 1 here:
Toast.makeText(getApplicationContext(), emailValid,
Toast.LENGTH_LONG).show();
}
private class validate extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... params)
{
// ... GET request produces string with either yes or no i.e. outcome
return outcome;
}
#Override
protected void onPostExecute (String s)
{
// Toast 2 here:
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
emailValid = s;
super.onPostExecute(s);
}
}
}
As requested, the detail in the doInBackground method is pasted below. The method actually return some XML. My original question which said "a string variable which is either a "yes" or "no"" was my attempt to simplify the setup. As I mentioned before, displaying the string in a Toast from within the onPostExecute works fine showing the participantXML sent from the doInBackground:
#Override
protected String doInBackground(String... params) {
InputStream inputStream;
String emailAddress = params[0];
String outcome = null;
HttpURLConnection httpURLConnection = null;
BufferedReader bufferedReader = null;
try
{
URL url = new URL("http://10.0.2.2:8080/project_name/webresources/entity.participant/email");
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("Accept", "application/xml");
httpURLConnection.addRequestProperty("Email-address", emailAddress);
httpURLConnection.connect();
inputStream = httpURLConnection.getInputStream();
StringBuffer stringBuffer = new StringBuffer();
if (inputStream == null) {
return null;
}
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line + "\n");
}
if (stringBuffer.length() == 0) {
return participantXML;
}
participantXML = stringBuffer.toString();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
validEmailAddress = participantXML;
return participantXML;
}
The answer by user3691697 to this question: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class? did the trick. I created task object (myTask) when executing the task and thereafter used it to assign the result to the variable like this:
AsyncTask myTask = new JoinActivity.validate.execute(email_et.getText().toString());
emailValid = myTask.get().toString();
The Toast message confirms that the assignment worked! Thank you for the help Pulak and LeoNeo.
I want to cancel an AsyncTask after a timeout if the task is still running and I want to cancel it immediately. Here is my code:
HttpURLConnection connection = null;
//GetRequestTask extends AsyncTask
final GetRequestsTask requestTask = new GetRequestsTask();
requestTask.execute(createUrl());
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("myapp", "entered handler");
if (requestTask.getStatus() == AsyncTask.Status.RUNNING) {
Log.d("myapp", "entered cancelling");
requestTask.cancel(true);
connection.disconnect();
}
}
}, TIME_OUT);
As you can see, I am calling a HTTP request in my AsyncTask's doInBackground method. and when I want to cancel the AsyncTask I also disconnect the connection.
The problem is that when I call cancel(true) and my app logs entered cancelling, the AsynkTask won't cancel immediately and will cancel with a minimum 10 to 20 seconds delay.
what should I do to cancel the task as soon as I call cancel?
UPDATE: This is my `AsyncTask code:
private class GetRequestsTask extends AsyncTask<URL, Void, JSONObject> {
#Override
protected void onPreExecute() {
Log.d("myapp", "entered onPreExecute");
mLoadingDialog.show();
}
#Override
protected JSONObject doInBackground(URL... urls) {
Log.d("myapp", "entered doInBackground");
try {
connection = (HttpURLConnection) urls[0].openConnection();
connection.setRequestProperty("Accept", "application/json");
int response = connection.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
try {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
reader.close();
}
return new JSONObject(builder.toString());
}
else {
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
Log.d("myapp", "entered onPostExecute");
mLoadingDialog.dismiss();
if (jsonObject == null) {
showNoInternetDialog();
}
else {
convertJSONtoArrayList(jsonObject);
mRequestArrayAdapter.notifyDataSetChanged();
mListView.smoothScrollToPosition(0);
}
}
#Override
protected void onCancelled() {
Log.d("myapp", "entered onCancelled");
mLoadingDialog.dismiss();
showNoInternetDialog();
}
The problem is that my timeout is 20 seconds, but onCancelled is called after 35, 40 seconds.
From this question:
If you're doing computations:
You have to check isCancelled() periodically.
If you're doing a HTTP request:
Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.
Additionally if you use some library to provide convenient requests, then I think it should have some cancel() method. For example, for retrofit there is such method.
So in this case like for 'If you're doing a HTTP request' section. you need to:
Save the instance of your request (for retrofit it's Call)
After calling cancel, call 'cancel' method for saved instance of request.
And one more alternative is rxJava. With help of this library you can create Observable for your request and save reference to its subscription. Then you just need to call savedSubscription.unsubscribe() and that's it.
Also, please, do not use Async tasks as inner classes.
In my code,first I access an address and I got the text file. In that, there are many picture links, such as http://dnight-math.stor.sinaapp.com/%E5%9C%B0%E7%90%861_img004.jpg. I use regular expression to find all the links to make a arraylist. Then I use downloadService to download all the pictures. When I first press a button to download ,it can run successfully. But it doesn't work if the button is pressed again and throws error. I think this bug is about thread but I don't know how to solve it.
HttpUtil.sendHttpRequest(address,
new HttpCallbackListener() {
#Override
public void onFinish(String response) {
try {
ArrayList<String> urlList = new ArrayList<>();
Pattern p = Pattern.compile("http:.*?.com/(.*?.(jpg|png))");
Matcher m = p.matcher(response);
StringBuffer buffer = new StringBuffer();
while (m.find()) {
m.appendReplacement(buffer, "<T>" + + m.group(1) + "</T>");
urlList.add(m.group());
}
m.appendTail(buffer);
response = buffer.toString();
Message m2 = Message.obtain();
m2.obj = response;
m2.what = 1;
mHandler.sendMessage(m2);
new DownloadService("/data/data/com.baodian/files",
urlList,
new DownloadStateListener() {
#Override
public void onFinish() {
}
#Override
public void onFailed() {
}
}, context).startDownload();
;
// JSONObject singleChoice=all.getjson
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onError(Exception e) {
}
});
public class HttpUtil {
public static void sendHttpRequest(final String address,
final HttpCallbackListener listener) {
new Thread(new Runnable() {
#Override
public void run() {
HttpURLConnection connection=null;
try {
URL url=new URL(address);
connection=(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream in=connection.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(in,"gbk"));
StringBuilder response=new StringBuilder();
String line=null;
while ((line=reader.readLine())!=null) {
response.append(line);
}
if (listener!=null) {
listener.onFinish(response.toString());
}
} catch (Exception e) {
if (listener != null) {
listener.onError(e);
}
}
}
}).start();
}
}
If you look at SimY4's answer here,
he says that the error you're getting "means the thread pool is busy and queue is full as well".
What you currently do is call onFailed when you encounter the error. What you can do is implement
a supplementary enqueing scheme. You can cache the newer urls until the thread queue has space, create and enqueue
the new threads at that point.
The following thread might prove useful : Java executors: how to be notified, without blocking, when a task completes?
Im attempting to read a text file from my onedrive, I need to check the version of the database and update if necessary.
This is an example of my code:
private void checkVersion() {
try {
int dbversion = prefs.getInt("dbversion", 1);
int dblastversion;
URL url = new URL("");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
str = in.readLine();
in.close();
System.out.println(str);
dblastversion = Integer.valueOf(str);
if (dbversion < dblastversion)
System.out.println("updates available");
} catch (IOException e) {
e.printStackTrace();
}
}
When I try to run the app crash and I got this error from logcat:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ex.example/com.ex.example.ActMenu}: android.os.NetworkOnMainThreadException
On this line
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
Somebody know what is the problem? Or its better use another cloud to stor the textfile. Thanks for the help.
UPDATE 2
Ok as GPRathour said I updated my code to this:
class Getversion_Async extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... arg0) {
System.out.println("starting");
try {
URL url = new URL("https://onedrive.live.com/redir?resid=b9186f8cb138a030!56556&authkey=!AFmrzOGv_OMArzo&ithint=file%2ctxt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
str = in.readLine();
in.close();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(final Void unused) {
System.out.println("ended");
}
}
And I call in th onCreate like this to test:
new Getversion_Async().execute();
Ok this code runs fine I use a site to host the file and the link ends with .txt and works fine but I cant edit the file. Somebody know how I can do this with onedrive?
The exception clearly says android.os.NetworkOnMainThreadException. To read file from server you need to perform some Network operation and it is not a good practice to perform it on Main Thread / UI Thread as it will hang the UI till the operation is performed.
What you need to do is, run this in AsyncTask
class LogoutUser_Async extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... arg0) {
// Do your network task here
return null;
}
#Override
protected void onPostExecute(final Void unused) {
// Process the result
}
}
I want to return false if the URL takes more then 5 seconds to connect - how is this possible using Java? Here is the code I am using to check if the URL is valid
HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
HttpURLConnection has a setConnectTimeout method.
Just set the timeout to 5000 milliseconds, and then catch java.net.SocketTimeoutException
Your code should look something like this:
try {
HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
con.setConnectTimeout(5000); //set timeout to 5 seconds
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
return false;
} catch (java.io.IOException e) {
return false;
}
You can set timeout like this,
con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
If the HTTP Connection doesn't timeout, You can implement the timeout checker in the background thread itself (AsyncTask, Service, etc), the following class is an example for Customize AsyncTask which timeout after certain period
public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
AsyncTask<Params, Progress, Result> {
private static final int HTTP_REQUEST_TIMEOUT = 30000;
#Override
protected Result doInBackground(Params... params) {
createTimeoutListener();
return doInBackgroundImpl(params);
}
private void createTimeoutListener() {
Thread timeout = new Thread() {
public void run() {
Looper.prepare();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (AsyncTaskWithTimer.this != null
&& AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
AsyncTaskWithTimer.this.cancel(true);
handler.removeCallbacks(this);
Looper.myLooper().quit();
}
}, HTTP_REQUEST_TIMEOUT);
Looper.loop();
}
};
timeout.start();
}
abstract protected Result doInBackgroundImpl(Params... params);
}
A Sample for this
public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {
#Override
protected void onCancelled(Void void) {
Log.d(TAG, "Async Task onCancelled With Result");
super.onCancelled(result);
}
#Override
protected void onCancelled() {
Log.d(TAG, "Async Task onCancelled");
super.onCancelled();
}
#Override
protected Void doInBackgroundImpl(Void... params) {
// Do background work
return null;
};
}
The System property sun.net.client.defaultConnectTimeout can be set. The value is in milliseconds. This will set a default timeout for each request-
Either by setting in JVM options-
-Dsun.net.client.defaultConnectTimeout=5000
OR in java code-
System.setProperty("sun.net.client.defaultConnectTimeout", "5000");
I could get solution for such a similar problem with addition of a simple line
HttpURLConnection hConn = (HttpURLConnection) url.openConnection();
hConn.setRequestMethod("HEAD");
My requirement was to know the response code and for that just getting the meta-information was sufficient, instead of getting the complete response body.
Default request method is GET and that was taking lot of time to return, finally throwing me SocketTimeoutException. The response was pretty fast when I set the Request Method to HEAD.