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().
Related
I need to perform a very simple operation that involve network. I know that this must be done with an Async Task, because run a task that involves Network operations on main thread is bad.
Since is pretty verbose using the classic way
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//to do
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//to do
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
for a method static method invocation that must download only few bits
I'm wondering if there is some more concise form or alternative that I could use.
You don't need an AsyncTask. It is just a convenience to use because it already has callback methods.
You can create a new Thread and execute your network call there.
There are many ways to create a worker thread. It depends on what are you doing with network.
If you just want to do simple network operations such as download some JSON data then get it back to update UI: use AsyncTask.
If you want to do long network operations which involve moderate to large amounts of data (either uploading or downloading): use Thread.
If you want to continuously send/receive message to/from the Internet, use HandlerThread.
So in conclusion: AsyncTask is already the simplest and easiest to use. Beside, you don't need to override all methods, just override doInBackGround() and onPostExecute() if you want to receive data.
See: Asynctask vs Thread in android
You can always use AsyncTask.execute(() -> { /* network operations */ });, the downside is you don't get any of the callbacks so I tend to only use this when prototyping or with very simple tasks.
Use an anonymous class inside a method:
public void asyncOperation () {
new AsyncTask<Task, Void, Boolean>() {
#Override
protected Boolean doInBackground(String... params) {
// Your background operation, network, database, etc
return true;
}
}.execute();
}
Context : networking(http request and response).
My question has two parts - one about volley and one about AsyncTask.
I'm learning to implement httpConnection using volley and AsyncTask, so please bear with me.
My question is, in what order the callbacks are called, after getting response from network? (In the case of volley and AsyncTask)
Are callbacks executed sequentially?
Consider this scenario,
I have 2 AsyncTasks. After getting response form network at same time, in what order callback will be called in postExecute()? Will both callbacks to UI thread will occur simultaneously as 2 Asynctasks are in seperate threads? or will they be executed sequentially?
I have read these SO posts,
can-i-do-a-synchronous-request-with-volley
multiple-asynctasks-onpostexecute-order
running-multiple-asynctasks-at-the-same-time-not-possible
how-to-manage-multiple-async-tasks-efficiently-in-android
how-to-synchronize-two-async-task
Thanks
Edit :
Consider this code of AsyncTask implementation,
public class AsyncTaskImplementation extends AsyncTask<String, Void, String> {
private final interface appAsyncTaskInterface;
public interface responseInterface {
void onSuccessHttpResponse(String resultJsonObject);
void onFailedHttpResponse(String failedMessage);
}
public AsyncTaskImplementation(){
//initialise
}
#Override
protected String doInBackground(String... params) {
//executeHttpRequest and return
}
#Override
protected void onPreExecute() {
//pre execute stuff like connection checking
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (result != null&& !result.equals("")) {
responseInterface.onSuccessResponse(result);
} else {
responseInterface.onFailedinterface("failed");
}
}
}
Question wrt to above code :
Consider two AsyncTaskImplementation objects, A and B created in a UI thread.
Now A and B will execute a http request (assume the code is implemented).
After that they will return response through interface responseInterface.
So my question is regarding this. Will A and B simultaneously invoke callback methods in UI thread through responseInterface?
Should I use synchronized to make sure that callbacks are synchronized? Or AsyncTask ensures that callbacks are invoked sequentially?
In my Android program, I have to do 4 or 5 network calls. Each are independent, and each can run on their own.
public void backGroundTasks() {
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<User> users = RetrofitAdapter.getClient().getUsersSync();
saveToDB(users);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<Media> contents = RetrofitAdapter.getClient().getContentsSync();
saveToDB(contents);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Profile profile = RetrofitAdapter.getClient().getProfile();
saveToDB(profile);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<Message> messages = RetrofitAdapter.getClient().getMessages();
saveToDB(messages);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
}
My questions are,
How this AsyncTask work ?
Will be executed in parallel ? or Will be invoked but the network requests will be queued ?
In some SO answers they have mentioned to do execute AsyncTasks with executeOnExecutor(). Will it help for this scenario ?
Note:
I use Retrofit library for making REST calls easier. Does it have anything with this problem ?
How this AsyncTask work ? Will be executed in parallel ?
Since honeycomb they will be executed serially, but if you will use executeOnExecutor then they will be executed in parallel.
or Will be invoked but the network requests will be queued ?
they will be queued, no network operation will start untill AsyncTask will get its turn.
Internally AsyncTasks use Executors. Your tasks only execute network operation, so you might switch to Executors. If you want to do your network operations serially, then you might also consider using IntentService.
This is answer by Arhimed. He explained it well.
AsyncTask uses a thread pool pattern for running the stuff from doInBackground(). The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously. Unfortunately I don't remember in what version exactly they changed that.
For more check his answer
Executors with AsyncTasks works like charm. It executes the network requests concurrently.
From the docs,
Since Honeycomb, invoking AsyncTask's executeOnExecutor() instead of execute() will execute tasks in parallel.
AsyncTask.THREAD_POOL_EXECUTOR
An Executor that can be used to execute tasks in parallel.
I am developing an Android application and when it launches :
1) I make an HTTP Request to my server to send a small JSON file.
2) Open a webView to show a URL.
When the server is running properly there is absolutely no problem and everything goes smoothly.
HOWEVER , if for any reason the server is down , the HTTP request literally hangs and i need to wait till there is an HTTP timeOut which is around 30seconds till i actually see the webView with the URL loading.
I read that i shouldn't make any networking inside the UI thread and i should use another thread for that.
In BlackBerry , that i have already developed the application for , this is as simple as that :
new Thread(){
public void run(){
HttpConnection hc =
(HttpConnection)Connector.open("http://www.stackoverflow.com");
}
}.start();
I just start a new thread and inside i make the requests and all the necessary networking. That way , even when my server is not reachable the webView is loaded immediately without making the user wait and sense that the app is actually hanging.
How could i do exactly the same in Android , easiest way possible ?
Why not to use the same method as you use it for BlackBerry?
new Thread() {
public void run() {
new URL("http://www.stackoverflow.com").getContent();
}
}.start();
Use AsyncTask, it's the simplest way to do that. For more details:
http://developer.android.com/reference/android/os/AsyncTask.html
In icecream sandwich and above you are not allowed to use any web cal in UI thread. However you may use threads, but best way proposed by android is to use Async task. A very simple example is as follow.
"AsyncTask < Parameters Type, Progress Value Type, Return Type >"
class MyAsyncTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
// Runs on UI thread- Any code you wants
// to execute before web service call. Put it here.
// Eg show progress dialog
}
#Override
protected String doInBackground(String... params) {
// Runs in background thread
String result = //your web service request;
return result;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String resp) {
// runs in UI thread - You may do what you want with response
// Eg Cancel progress dialog - Use result
}
}
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.