Android: Communication and coordination between UI-thread and other thread - android

I'm using this AsyncTask for calling the skype page https://login.skype.com/json/validator?new_username=username for understand if a certain skype contact already exsists.
public class SkypeValidateUserTask extends AsyncTask<String, Void, String>{
protected String doInBackground(String...urls){
String response = "";
for(String url:urls){
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try{
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s="";
while((s=buffer.readLine()) != null){
response+=s;
}
}catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
public void onPostExecute(String result){
String status="";
try{
JSONObject obj=new JSONObject(result);
status=obj.getString("status");
}catch(Exception ex){
ex.printStackTrace();
}
//Log.i("RISULTATO: ","STATO: "+status);
}
}
The main activity call this task for getting skype validation user result. The code is:
String skype = "name.surname.example";
if(!skype.equalsIgnoreCase("")){
// check if the skype contact exists
SkypeValidateUserTask task = new SkypeValidateUserTask();
task.execute(new String[] {"https://login.skype.com/json/validator?new_username="+skype});
// here I need to obtain the result of the thread
}
My problems are:
I need to get the result of the task (the String status) in the main activity.
After the task.execute call, the next code in main activity is executed without wait for result returned from asynctask.

It is dengerious to use get() method to get the result from async task because It blocks the UI Thread.
use This Thread where I provided a reusable solutionCallback mechanism to get result from async thread without blocking UI Thread
I have implemented that with the help of lapslaz
public JsonData(YourActivityClass activity)
{
this.activity=activity;
mProgressDialog = new ProgressDialog(activity);
}
protected void onPostExecute(String jsondata) {
if (mProgressDialog != null || mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
if(jsondata!=null) {
activity.yourcallback(jsondata)
}
}
And define the yourcallback() in YourActivityClass
private void yourcallback(String data) {
jsonRecordsData=data;
showRecordsFromJson();
}

Start your AsyncTask on the main thread. In the preExecute method of the AsyncTask, you can start a ProgressDialog to indicate to the user that you're doing something that takes a few seconds. Use doInBackground to perform the long-running task (checking for valid Skype username, in your case). When it is complete, onPostExecute will be called. Since this runs on the UI thread, you can handle the result and perform further actions depending on it. Don't forget to close the ProgressDialog in onPostExecute.

That's why asyncTask is here. You can not make a blocking function call in UI thread because that will make your app unresponsive.

OnPostExcute Method is called on the UI/Main thread. you need to move your logic there to continue analyzing the result.

If your AsyncTask is an inner class of your main activity then you can just call a function in the main activity and pass it the result
Since it looks like it isn't, you can create constructor in your Async and pass it the Context from your main activity so you can pass the variable back to main activity
Also, the purpose of the AyncTask is to not block your UI thread, put your logic in a separate function that the AsyncTask will call

You need to implement a call-back mechanism in your AsyncTask. So instead of this:
task.execute(...);
// use results of task
Your structure should be:
task.execute(...);
// go do something else while task has a chance to execute
public void statusAvailable(String status) {
// use results of task
}
and in onPostExecute:
public void onPostExecute(String result) {
. . .
status=obj.getString("status");
activity.statusAvailable(status);
}

Getting the result out of the AsyncTask is easy . . . just the Google docs don't make it clear how to do it. Here's a quick run down.
task.execute(params);
will start the AsyncTask and pass to the doInBackground method whatever parameters you include. Once doInBackground finishes, it passes the result of its functions to onPostExecute. One would think that onPostExecute would be able to just return whatever you sent it. It doesn't. To get the result of doInBackground, which was sent to onPostExecute you need to call
task.get();
the .get() method automaticlly waits until the task has completed execution and then returns whatever the result of onPostExecute is back to the UI thread. You can assign the result to whatever variable you want and use normally after that - for example
JSONObject skypeStuff = task.get()
Put another way - just like the AsynTask does not start on it's own, it does not return on its own. The same way you need to .execute() from the UI thread, you need to call .get() from the UI thread to extract the result of the task.

Related

ProgressDialog in AsyncTask onPreExecute, but it appears after doInBackground

This is part of my application. (You can run code below as an isolated application) On that website (url), using php language, parse some numbers from other website, and make an array and encode it to JSON array, and show.
But, with the code below (without dismiss function!) ProgressDialog appears after doInBackground.
When I add dismiss function to onPostExecute like below, it never appears. But When I set log for checking dialog window, it says that there was an dialog.
I heard that doInBackground freezes UI, but it freezes before dialog is shown.
Other similar questions have found solution, erasing .get() from mAsyncTask().execute().get(), but I don't have any get() in my code.
Boolean variable loadfinish is for waiting finishing asynctask, to show results from that website after asynctask. If I delete
while(loadFinish == false)
there, it automacally appears and disappears very well, but I can't show result immediately...
Add) I found that it takes several seconds to dialog appear after doInBackground... why?!
Add2) I've tried to move dialog codes before and after new mAsyncTask().execute(), but it doesn't work too...
public class MainActivity extends Activity {
boolean loadFinish;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start = (Button) findViewById(R.id.start);
//just a button for starting asynctask
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadFinish = false;
new mAsyncTask().execute();
// get and make json array to java array
while (loadFinish == false)
;
}
});
// add array to Custom_List_Data, and set custom row_adapter to listView.
// if I delete while(loadFinish == false), array with initial data is added.
}
private class mAsyncTask extends AsyncTask<String, String, String> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("asdf");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected String doInBackground(String... params) {
String url = "http://songdosiyak.url.ph/MouiRate/etoos/3/main/";
String response_str = "";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
try {
response_str = client.execute(request, responseHandler);
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
loadFinish = true;
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dialog.dismiss();
}
}
}
Sorry for my poor English language skill and thank you for reading!
As Gabe mentioned you don't need the loop, all you need is some more understanding what the async methods should do.
You introduced the result, because you want to display the result. All you have to do is to return your response_str in doInBackground. It will be then available to you as a param to onPostExecute where you can easily display it, or do whatever you need to do with it.
So to summarize:
Remove the loop
Return value response_str or whatever from doInBackground
Display value in onPostExecute
And remove loadFinish variable as its not needed at all
Hope that helps.
Because you're using an AsyncTask totally wrong. You're busy looping waiting for it to finish. NEVER do that- if you're doing that there's no point in using an AsyncTask. At any rate, the reason it won't appear is that the UI doesn't update until the UI thread returns to the event loop inside the Android Framework and runs the drawing code, which happens after onClick returns. So you won't draw until your busy loop exits, which happens after doInBackground finishes.
The solution is to remove the loop waiting for the AsyncTask to finish in your onClick. If you have logic that needs to run after it, put it in onPostExecute.
It may be worth looking into using an async library.
Using a library to help handle async callbacks can be super helpful for this as you can start the spinner, call your api, then stop the spinner in either the onSuccess function, or your success callback method in your class.
This is the one I usually use:
LoopJ's Async HTTP Callback Library
This will handle GET and POST requests with a lot of cool features such as custom timeouts, JSON format, onSuccess() and onFailure() methods, etc. There's a lot of working examples of this library too. I've used it in all my apps and haven't had any problems yet!
Hopefully this helps.

Android AsyncTask: what is difference between execute() and get()?

Should I write smth like that
return task.exec(session, state).get(json_timeout, TimeUnit.MILLISECONDS);
Or I can do like this
task.exec(session, state, result);
return result;
A have already read all documentation that I found, but failed to find an answer. My bad...
Do not use get(). It will block the ui thread until asynctask finishes execution which no longer makes it asynchronous.
Use execute and to invoke asynctask
new task().exec(session, state, result);
Also you can pass the params to the constructor of asynctask or to doInbackground()
http://developer.android.com/reference/android/os/AsyncTask.html
public final Result get ()
Added in API level 3
Waits if necessary for the computation to complete, and then retrieves its result.
You can make your asynctask an inner class of your activity class and update ui in onPostExecute.
If asynctask is in a different file then you can use interface.
How do I return a boolean from AsyncTask?
AsyncTask#get() will block the calling thread.
AsyncTask#execute() will run in a separate thread and deliver the Result in onPostExecute(...).
I would recommend against using the get() method except in special cases like testing. The whole purpose of the AsyncTask is to execute some long-running operation in doInBackground() then handle the result once it's finished.
One example of normal AsyncTask execution would look like:
Task task = new Task(){
#Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
//handle your result here
}
};
task.execute();

How to return value from async task in android

I created an async task to call my server to get data from DB.
I need to process the result returned from http server call.
From my activity i calling the async task in many places. so i cant use member variable to access the result. is there any way to do?
public Result CallServer(String params)
{
try
{
new MainAynscTask().execute(params);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return aResultM;//Need to get back the result
}
private class MainAynscTask extends AsyncTask<String, Void, Result> {
#Override
protected Result doInBackground(String... ParamsP) {
//calling server codes
return aResultL;
}
#Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
//how i will pass this result where i called this task?
}
Try to call the get() method of AsyncTask after you call the execute() method. This works for me
http://developer.android.com/reference/android/os/AsyncTask.html#get()
public Result CallServer(String params)
{
try
{
MainAynscTask task = new MainAynscTask();
task.execute(params);
Result aResultM = task.get(); //Add this
}
catch(Exception ex)
{
ex.printStackTrace();
}
return aResultM;//Need to get back the result
}
...
...
There are two ways i can suggest -
onPostExecute(Result) in AsyncTask. See http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)
Send a broadcast with the result as an extra.
AsyncTask is an asynchronous task so it does NOT make sense to return the result to the caller. Rather handle the result in onPostExecute() like setting the value to TextView etc. Or send a broadcast so that some other listener can handle the result.
Here's how I got around this:
1) Create an interface class that defines a signature for a method to execute on completion:
public interface AsyncIfc {
public void onComplete();
}
2) Set a property on your AsyncTask class to hold the delegate method:
public AsyncIfc completionCode;
3) Trigger the delegate from onPostExecute() in the AsyncTask:
completionCode.onComplete();
4) From your calling logic, set the delegate property to an anonymous method:
task.completionCode = new AsyncIfc() {
#Override
public void onComplete() {
// Any logic you want to happen after execution
}
};
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
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.
Use a handler
In your activity
Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
String s=(String)msg.obj;
tv.setText(s);
}
};
//result is soap object in this case.
protected void onPostExecute(SoapObject result) {
pd.dismiss();
if(result != null) {
Message msg=new Message();
msg.obj=result.getProperty(0).toString();
mHandler.sendMessage(msg);
}

AsyncTask to call another function within class

Basically, do I have to put code I want to run on another thread inside doInBackground, or can I call another function/class/whatever-it-is-functions-are-called-in-JAVA within doInBackground and have it run asynchronously? IE: (example code I found online)
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
return null;
}
is how I have seen it done, but can I instead do:
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
and have it call a function I already wrote and then have that function run in another thread? Sometimes my HTTP server is a bit slow to respond (it is but a lowly testing server at the moment) and Android automatically pops up the kill process box if my postToServer() call takes more than 5 seconds, and also disables my UI until the postToServer() call finishes. This is a problem because I am developing a GPS tracking app (internally for the company I work for) and the UI option to shut the tracking off freezes until my postToServer() finishes, which sometimes doesn't ever happen. I apologize if this has been answered, I tried searching but haven't found any examples that work the way I'm hoping to make this work.
You can do that, but you will have to move the UI updates to onPostExecute as it is run on the UI thread.
public MyAsyncTask extends AsyncTask<foo, bar, baz> {
...
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
protected void onPostExecute(Long result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
....
}
You may want to pass in the TextView to the constructor of the AsyncTask and store it as a WeakReference.
private final WeakReference textViewReference;
public MyAsyncTask(TextView txt) {
textViewReference = new WeakReference<TextView>(txt);
}
And then in onPostExecute you would make sure that the TextView reference still exists.
protected void onPostExecute(Long result) {
TextView txt = textViewReference.get();
if (txt != null)
txt.setText("Executed");
}
If you want to notify the user that the task is executing I would put that before invoking the AsyncTask.
myTextView.setText("Update in progress...");
new MyAsyncTask().execute();
then in onPostExecute set the TextView to say "Update complete."
Have you tried it the second way?
From what you've posted it seems like it should work fine how you have it in the second example.
However (perhaps unrelated to your question?) in your first example I think it will fail because you are trying to change the UI from a background thread. You'd want to put the parts that manipulate the TextView inside of onPostExecute() rather than doInBackground()
Yes you can, the call to your postToServer method (that's the name in java) will run off the main thread.
Everything inside the doInBackground method of an AsyncTask is run on a pooled thread, but be sure to NOT invoke it directly! Call execute on your asynktask instead, the android framework will do the work for you and run doInBackground on another thread.
try doing something like this:
new AsyncTask<Void, Void, Void>() {
#Override
// this runs on another thread
protected Void doInBackground(Void... params) {
// assuming x, y, z, h are visible here
postToServer(x, y, z, h);
return null;
}
#Override
// this runs on main thread
protected void onPostExecute(Void result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
}.execute(); // call execute, NOT doInBackGround
Also, notice that every other method of AsyncTask, such as onPostExecute runs on the main thread, so avoid heavy loading them.
Basically The Bottom Line Is the doInBackground() method is Can't interact with The Ui Thread Or The Main thread. that's Why When You are Try To Interact With The TextView in doInBackground () it Will Crash the UI Thread Cuz It's Illegal.
so if anytime You want to Interact with the UI Thread,When You are Working on doInBackground You need to Override
OnPostExecute() //this Function is Called when The doInBackground Function job is Done.
So You can Update The UI Thread Content By this When You're Job is Done In doInBackground () or You are In doInBackground ()

sequencing asynctasks

I understand that http requests should be run as part of an AsyncTask to keep it off the the UI thread. But what about the case where multiple and sequential http requests may be necessary, where the latter http requests depend on the earlier, and therefore need to be run sequentially?
In this case, is it best to put the latter AsyncTasks in the onPostExecute of the earlier AsyncTasks, to make them run sequentially?
Or does this indicate that I have the wrong approach?
To make a lot of HTTPRequests in a queue, try this:
private class QueueExample extends AsyncTask<URL, InputStream, Long> {
protected Long doInBackground(URL... urls) {
SynchronousQueue<URL> queue = new SynchronousQueue<URL>();
for(URL url : urls){
queue.add(url);
}
for (URL url : queue) {
InputStream in = new BufferedInputStream(queue.take().openConnection().getInputStream());
publishProgress(in);
}
}
protected void onProgressUpdate(InputStream... progress) {
doSomethingWithStream(progress[0]);
//Do Something
}
protected void onPostExecute(Long result) {
//Finished
}
}
If you don't have to update the UI between requests, just execute them one after another in doInBackground() and accumulate the results. When done, just return and use the result in onPostExecute() to update the UI. If you do need to update the UI, you can call publishProgress when you get some intermediate result and update in onProgressUpdate().

Categories

Resources