When my users click the login button I want to hit my webservice. I have the following code to do so.
public void onClick(final View view) {
String orgKey = inputCompany.getText().toString();
new getAppInfo().execute("http://example.webservice.com");
Here is my getAppInfo
private class getAppInfo extends AsyncTask<String, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
#Override
protected String doInBackground(String... urls) {
String xml = null;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urls[0]);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// return XML
return xml;
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
#Override
protected void onPostExecute(String result) {
Document doc = GetDomElement(result); // getting DOM element
NodeList nl = doc.getElementsByTagName("details");
getChildElements(nl);
}
The doBackground is running but the onPostExecute is not. I have moved it out of the on click and it has worked but I need it inside the onClick.
How can I get it to run the onPostExecute inside my onClick?
The syntax is correct you might be getting an exception in the background process, stopping the background thread. put a log statement at the end of your doInBackground or add a catch (Throwable t) to your try.
Have faith - it WILL be called as long as doInBackground completes successfully.
As an aside, you should do your DOM parse in the background as well - at the moment you are doing it in the UI thread which may cause ANR popups.
First, a general pointer - class names in Java are conventionally capitalized CamelCase, method names are lowercase camelCase.
On to your question - are you by any chance exiting the Activity or closing the Dialog that spawned the task? If it works outside that onclick handler, my guess is that something is destroying the Handler object that the AsyncTask is trying to execute that method on.
Try posting a Runnable (which executes the AsyncTask) on the current Activity's Handler.
onPostExecute will always be called once doInBackground is completed. Try to Log something in onPostExecute to confirm this behavior.
add a general catch statement in your doInBackground method.
catch(Exception e){
e.printStackTrace();
}
Related
I need to display "Wait a moment..." message via Toast while the app tries to fetch some data from the internet that can take couples of seconds depending on the internet connection and the load on the server.
the http connection is made through a AsyncTask.
What I am doing is that I display the message by : "Toast.makeText" method, then I enter a "while" loop that breaks when the execute method of the AsyncTask finishes, then I display some results on the Activity.
The problem is that the Toast dosen't appear until the while loop breaks!
I tried to replace the Toast with displaying the message in TextView with setText , but the same happened, the message displayed after the while loop breaks!
any thoughts? My Code looks like this:
waitToast = Toast.makeText(this,R.string.WaitText, Toast.LENGTH_SHORT);
waitToast.show();
.........
.........
new DownloadFilesTask().execute();
dataRetrieved = false;
while (!dataRetrieved){ }
........
And in the doInBackground:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
InputStream in = null;
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(4000);
in = urlConnection.getInputStream();
in = new BufferedInputStream(urlConnection.getInputStream());
url_input = readStream(in);
........
catch (Exception e) {
e.printStackTrace();
}
finally{
dataRetrieved = true;
urlConnection.disconnect();
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Do not do this. You are blocking the ui thread with your while loop. That's why your Toast does not show up.
Remove your while and override onPostExecute() in your AsyncTask. This methods runs on the Ui thread, unlike doInbackground so you can update Activity UI.
use this method in asynktask:
#Override
protected void onPreExecute() {
super.onPreExecute();
// Show Toast
Toast.makeText(context,"text",Toast.LENGTH_LONG).show();
}
And remember "onPostExecute" and "onPreExecute" Can Change UI , Don't Change UI At "doInBackground" .
I'm developing an android application , my problem is that I can't execute my asyntask class after clicking on a button but it works normally when I called it in my program
I have in logcat the error : "Only the original thread that created a view hierarchy can touch its views.”
here is my class :
ts.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
jr=2;
emp trs=new emp();
trs.execute();
}
});
emp t=new emp();
t.execute();
private class emp extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params) {
try{
url = new URL("....");
HttpURLConnection httpconn = (HttpURLConnection)url.openConnection();
httpconn.connect();
if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK){
BufferedReader input = new BufferedReader(new InputStreamReader(httpconn.getInputStream()),8192);
while ((line = input.readLine()) != null) {
ja = new JSONArray(line);}
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = null;j=0;
jo = (JSONObject) ja.getJSONObject(i);
ch = jo.getString("bgcolor");
ch1=jo.getString("duree_heure");
ch2=jo.getString("debut_heure");
ch4=jo.getString("matiere");
j=Integer.parseInt(ch2);
ch2=trans(j,ch1);
ch5=jo.getString("idsalle");
ch6=salle(ch5);
addvi(v,ch,ch6,ch2,ch4);
}
input.close();
}
}catch (JSONException e){
System.out.print("vérifier !");e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
return null;
}
}
so can anyone helps me please ?
It's caused by the fact that when you are inside doInBackground you are inside another thread too and since it's forbidden to edit/remove/etc views create from another thread (in this case UI thread) it throw this error.
Since you didn't posted the full code, the only thing which could case this problem is addvi(v,ch,ch6,ch2,ch4); so you should use runOnUiThread method of Activity to execute the method from the main thread.
But you should rethink your logic to work better with Asynctask methods onPreExecute / onPostExecute which is used to work with UI and are called and execute in the main thread (UI thread).
P.S To work better with the methods i said above, you should know what means the three generic in the extendsAsyncTask<Params, Progress, Result>
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
Edit: As other noticed in comments you have onProgressUpdate too which is invoked by you from doBackground method using publishProgress
you cannot touch or modify view in the doInBackground function of asynctask all UI work need to be done on UI thread or main thread.I think you are doing some UI work so do it in onPostExecute() method
This is my code
every time i touch the imageview my app waits about 5 secs and then chrashes
I have the INTERNET permission
On the server side i have a php page that reads the GET and insert it in a database
public class Home extends Activity {
ImageView lightbut;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ImageView lightbut = (ImageView) findViewById(R.id.light);
lightbut.setClickable(true);
lightbut.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("== My activity ===","OnClick is called");
// Creating HTTP client
HttpClient httpClient = new DefaultHttpClient();
// Creating HTTP Post
HttpGet httpPost = new HttpGet("http://192.168.0.102/HR/index.php?command=ligthsoff");
try {
HttpResponse response = httpClient.execute(httpPost);
} catch (ClientProtocolException e) {
// writing exception to log
e.printStackTrace();
} catch (IOException e) {
// writing exception to log
e.printStackTrace();
}
}
});
}
A logcat would be very helpful but its probably from doing network stuff on the UI. You should move all of your network code to a background Thread such as an AsyncTask. This will easily allow you to do the network stuff in the background then update the UI if needed in functions that run on the UI.
AsyncTask Docs
Here is an answer that shows the basic structure. Basically, you call the AsyncTask from the UI such as in your onClick() then you do network operations in doInBackground() which is called when the task first starts then you can update the UI in any of its other methods.
Using the example I referenced, you would just put all of your network stuff, which looks like everything in your onClick(), inside the doInBackground() method of the example in the link. Then in your onClick() you would do something like
lightbut.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
TalkToServer task = new TalkToServer(); // could pass params to constructor here but might not be needed in this situation
task.execute(); // could pass in params for `doInBackground()` such as url, etc... but again maybe not needed for this situation
}
I'm trying to get an xml from a url, but I have a bug in HttpResponse.
The URL is for example as follows:
http://maps.googleapis.com/maps/api/directions/xml?origin=43.364876,-5.8654205&destination=43.545686,-5.664482&sensor=true
And my code is:
public String getXML (String url){
String result = null;
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpPost = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
result = EntityUtils.toString(httpEntity);
} catch (Exception ex) {
Toast errorToast =
Toast.makeText(getApplicationContext(),
"Error reading xml", Toast.LENGTH_LONG);
errorToast.show();
}
return result;
}
I've already set the internet permission in the manifest.
The error is in the line:
HttpResponse httpResponse = httpClient.execute(httpPost);
and shows an error:
android.os.NetworkOnMainThreadException
Thank you
You should create a new thread as fetching the data could take a long time, thus blocking the UI thread. This is reason why you get android.os.NetworkOnMainThreadException.
Try this,
new Thread(new Runnable() {
#Override
public void run() {
// Your code here.
}
}).start();
Alternative to this solution is using AsyncTask, which is provided in android. It has doInBackground method which runs on a background thread.
Instead of calling getXML(); directly, you write this snippet in your main method:
{
...
String[] params = new String[]{url};
AsyncPostData apd = new AsyncPostData ();
apd.execute(params);
...
}
Define your Async Task like below:
private class AsyncPostData extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
getXML (params[0])
return null;
}
}
I think we have a same query here
cant get xml file from an URL in android
I'll just repost this from a different question asked earlier today:
You're trying to run a network request on the main UI thread. Android does not allow you to do that since 3.0 (I believe). Doing so causes your UI to lock up until the request is completed, rendering your app useless during the execution of the request.
You'll either have to run your request in a new Thread or an ASyncTask, to take the load of the UI thread. You can find more info on how to use multiple threads here.
Android Devices with 4+ OS versions not allows to call webservices from main activity.
your have HTTP request on activity, so you have got "android.os.NetworkOnMainThreadException"
I recommend you go for the AsyncTask solution. It is an easy and straightforward way of running requests or any other background tasks and calling web services using devices having latest OS virsion you must need to use AsyncTask.
It's also easy to implement e.g. onProgressUpdate if you need to show a progress bar of some sort while running your requests.
private class YourTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
//call your methods from here
//publish yor progress here..
publishProgress((int) ((i / (float) count) * 100));
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//action after execution success or not
}
}
#Override
protected InputStream doInBackground(String... url){
try {
InputStream stream = downloadXml(url[0]);
new ParseXml(stream); //for testing porpuses: outputs ok to logcat
return stream;
} catch (IOException e) {
Log.d("dbg","exception");
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(InputStream result) {
if (result != null) {
new ParseXml(result); //crashes the app
}
Log.d("dbg","postexecute triggered ok");
}
Code is pretty self explanatory i think, i tried changing the passing type to just Object and type casted it where needed but it didn't worked either.
Is there anything undocumented in sdk that i should know of ?
obviously, Crash.. You are doing lengthy (also may be network related) operation in MainUI Thread. as onPostExecute() of AsyncTask runs on In MainUI Thread only. So always keep it in doInBackground().
This code line new ParseXml(result); should be in doInBackground() of AsyncTask.
Update:
So complete the Parsing of XML in doInBackground() and only pass the result in onPostExecute() if only you want to reflect the updation on Application UI.