I have an app, which uses several HTTPRequests for example
get a session id
get some locationdata
get existing categories
(...) and some more
I created a HTTPRequestHandler, which basically manages all the AsynTasks for each Request... This works well, but my problem is, I don't know a good way for managing the different AsynTasks. For example, you need to get the SessionId Task before you can start the GetSomeLocationData Task
So in my HTTPRequestHandler I have a queue, which starts the depending AsyncTasks like:
private void startSessionIdTask(...) {
//...
GetSessionIdTask mGetSessionIdTask = new GetSessionIdTask(this);
mGetSessionIdTask.execute(url);
}
//and from the postExecute() in GetSessionIdTask I call
public void setSessionId(int mSessionId) {
mDataHelper.setmSessionId(mSessionId); //set id
String url = API_URL + API_GET_FAVORITES + URL_VARIABLE;
List<NameValuePair> params = new LinkedList<NameValuePair>();
params.add(new BasicNameValuePair("session_id", getSessionId()));
String paramString = URLEncodedUtils.format(params, "utf-8");
url += paramString;
//and finally start another Tasks (and so one...)
GetLocationsTask mGetLocationsTask = new GetLocationsTask(this);
mGetSessionIdTask.execute(url);
}
However, this works fine, but the problem is, that (depending on the connection), this queue takes time, and the user can start other AsynTasks which fail, because some initially data is not loaded yet.
I could set some Boolean like isSessionIdLoaded or could block the UI for the user, but I'm wondering, if there s any better solution?!
So my question is: Is there a way to put asyntasks in some kind of queue (ArrayList, Map..) which will be executed in a row?
As of Android 3+ AsyncTasks will be executed in serial on the AsyncTask.SERIAL_EXECUTOR. So by default if you start 2 AsyncTasks
task1.execute();
task2.execute();
Task2 will only be executed if task1 has finished (just check the sdk implementaion of AsyncTask.SERIAL_EXECUTOR). This can be pushed to that point, that if task1 for any reason never finishes, task2 will never start and you have deadlocked your app.
If you want your own queue independed from the default SERIAL_EXECUTOR, just use
public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)
And provide your own executor (aka threadpool). For one project I copyed the SERIAL_EXECUTOR implementation to have 2 serial queues.
For Android 2.3 to 1.6 all tasks are by default in parallel, similiar to calling in Android 3+:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,null);
Unfortunatly in Android 2.3 und lower you have no option of specifing the executor on which the task/thread will be run on. So if you want to have it done serially, you have to implement it yourself, by calling task2 only after task1 has finished explicitly in onPostExecute(). This concept can of course be pushed to use a queue of task where the former task will call the next one when it's finished (= serial worker queue). For this you will find plenty literature and patterns.
I'm not entirely sure what you're asking, but if you'd just like a way to queue up Runnables to execute in a background thread in sequence, then Executors.newSingleThreadExecutor() may be what you're looking for. It's more complicated than it probably needs to be, but you can find examples and tutorials easily enough via google.
If you need sequential execution, I'd recommend switching to IntentService instead of using AsyncTask. See docs: http://developer.android.com/reference/android/app/IntentService.html
Related
i am new on xamarin android apps.I want to build an app and i have read that connections with database or the execution of queries should happen asynchronously from the main thread otherwise the UIthread will may collapse.I have found 2 ways to do that:
First way:
WebClient client = new WebClient();
Uri uri = new Uri("http://192.168.2.8/CreateUsername.php");
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Name", txtname.text);
client.UploadValuesCompleted += Client_UploadValuesCompleted;
client.UploadValuesAsync(uri,parameters); ---> is this gonna create a new thread and run asynchronously???
(here i found the first way: https://www.youtube.com/watch?v=jF3D__ibrx8 )
SecondWay:
https://developer.xamarin.com/recipes/android/web_services/consuming_services/call_a_rest_web_service/
Both ways are correct?both of ways are gonna create a new thread and run asynchronously?Thanks!!!!
Both examples are ok but I'd usually trust the official documentation by Xamarin first. What might confuse you with the first example is the lack of await keyword when calling the UploadValuesAsync method. Here's what actually happens:
Call to UploadValuesAsync is made from the UI thread.
UI thread blocks until the method returns because it's running synchronously.
However, the method returns very quickly because it launches the upload process asynchronously on another thread internally and doesn't wait for the process to complete.
When the whole upload process is finished, Client_UploadValuesCompleted will be called.
As you can see on the WebClient.UploadValuesAsync page on MSDN, it states that:
These methods do not block the calling thread.
Also, when looking at the source code for UploadValuesAsync, you'll notice the following attribute defined on top:
[HostProtection(ExternalThreading=true)]
which means the following:
Code that exposes external threading creates or manipulates threads other than its own, which might be harmful to the host.
To sum it up, the upload process is handled on another background thread but otherwise, your code will run synchronously. There's a bit more asynchronicity going on in Xamarin's sample.
I have an IP scanning routine to find web servers on a LAN, then based on the results of this scan, I need to determine which IP address is the one I am looking for by running a second async task in the onPostExecute of the IP scanning routine.
The IP is hard coded at this stage but I will be using an Array to store the scan results and use the array to try each IP in sequence as soon as I get this core logic to work.
The first async task finishes like this:
#Override
protected void onPostExecute(String s) {
progressBarServerScan.setProgress(Integer.valueOf(100));
tvScanProgressText.setText("Server scan progress " + "100" + " %");
//must try home dir, I hope all will be "home"...else must manage different folders
// check for each system type
String serverCheck = "http://192.168.0.12/home";
new identifyServer().execute(serverCheck);
if (systemNameScan!="Unknown"){
Toast.makeText(getBaseContext(),"Found "+systemNameScan+" system at "+serverCheck,Toast.LENGTH_SHORT).show();
}
As you can see, it launches the second asyncTask which checks for key words in the HTTP response to indentify if each of the found IP addresses are the one I am looking for. The 2nd async taks ends like this:
#Override
protected void onPostExecute(String result) {
Pattern HPPattern = Pattern.compile("Visit\\sthe\\sHewlett\\sPackard\\swebsite.*");
Matcher mHP = HPPattern.matcher(result);
if (mHP.find()) {
systemNameScan = "Hewlett Packard";
Toast.makeText(getBaseContext(),"systemNameScan is: "+systemNameScan,Toast.LENGTH_LONG).show();
} else {
systemNameScan = "Unknown";
Toast.makeText(getBaseContext(),"systemNameScan is: "+systemNameScan,Toast.LENGTH_LONG).show();
//offer option to post the HTML page found to the developer
// for analysis
}
The issue I am facing is that the Toast msg of the calling routine executes before the one in the sub-routine, and the variable I am updating in the sub-routine is apparently not yet updated when I am testing for its contents in the if statement "if (systemNameScan!="Unknown"){...etc. The value of systemNameScan is null at that stage so my check is not working...
Can someone explain why the calling routine is proceeding before the second async task onPostExecute has fully completed? and more importantly, how can I better structure this IP scanning task and subsequent contents analysis of the web pages to avoid this timing issue?
I tried to move the checking routine to the 2nd async task but then I couldn't find a way to use the IP address that was passed to the async task as the variable "serverCheck" is not known to the 2nd Async task...
I see 2 questions:
1) Can someone explain why the calling routine is proceeding before the second async task onPostExecute has fully completed?
Because the call
new identifyServer().execute(serverCheck);
only starts the identifyServer task. This call returns after starting the task on a separate thread. Thus, in the calling thread (i.e. the thread that is executing the onPostExecute method of the first task), the display of the Toast is the next code to execute. As you observed, the timing is such that this sometimes will display before the 2nd task is complete.
2) how can I better structure this IP scanning task and subsequent contents analysis of the web pages to avoid this timing issue?
Moving the checking routine to the 2nd task was problematic, because as you stated: the variable "serverCheck" is not known to the 2nd Async task. So you could make it known by saving it as an instance variable:
// Note I took the liberty of renaming this class to start with a
// capital letter. This is a Java convention.
class IdentifyServerTask extends AsyncTask<String, Integer, String> {
private String serverCheck;
public IdentifyServerTask(String IdentifyServerTask) {
this.serverCheck = serverCheck;
}
}
And now the serverCheck value is required to create an instance of the task:
IdentifyServerTask task2 = new IdentifyServerTask(serverCheck);
task.execute(serverCheck);
For example there is an AsyncTask of a String... parameters , if I make a call like this :
AsyncTask<String, Void, Void> someTask = new myTask(myActivity.this);
someTask.execute(string1 , string2 , string3);
What is the internal order of execution of the doInBackground inside this task : does it treat string1 first then string2 and so on sequencely as they are provided when called , or does it treat the parameters randomly ?
First thing, parameters are not passed randomly. This answer will explain you more about parameters. Also check image from this answer. I am adding same image here for your understanding.
It may be serial on one thread or parallel, it actually depends upon which version of Android OS your app is running. For most of the case it would be serial on one background thread.
This is what google document says :-
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
Note: this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting HONEYCOMB, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution. If you truly want parallel execution, you can use the executeOnExecutor(Executor, Params...) version of this method with THREAD_POOL_EXECUTOR; however, see commentary there for warnings on its use.
This method must be invoked on the UI thread.
Check this link execute (Params... params) it will help you.
Hope it helps,
Thanks.
String... is a "vararg", which in this example converts all individual parameters into a String[], where the entries to the array are in the order they got passed into the method.
So using your example, (String[]) param[0] == string1, param[1] == string2, param[2] == string3 and so forth. This is for the ordering of param entries, as to how each entry in param is used, it depends entirely on your code.
I have severals URLs I need to get data from, this should happen in order, one by one. The amount of data returned by requesting those URLs is relatively big. I need to be able to reschedule particular downloads which failed.
What is the best way to go? Shall I use IntentService, Loaders or something else?
Additional note: I would need not only to download, but also post process the data (create tables in db, fill it with data, etc). So DownloadManger can't be of help here.
I would use an IntentService.
It has a number of advantages that are suitable for your needs, including being able to download the data without your application running and supporting automatic restart of the service using setIntentRedelivery().
You can set a number of identifiers for the particular job, you need to perform using Intent extras, and you can keep track of the progress using SharedPreferences - that way you can also resume the work if it's been cancelled previously.
The easiest way is probably to use the system DownloadManager http://developer.android.com/reference/android/app/DownloadManager.html
(answering from my phone, so please excuse the lack of formatting)
I would suggest a service for this. Having service resolves many problems
It would allow reporting of progress asynchronously to the application so you can enable or disable a specific gui in application based on the download status of data
It will allow you to continue the download even if the user switches to other application or closes the application.
Will allow you to establish independent communication with server to prioritize downloads without user interaction.
Try a WakefulIntentService for creating a long-running job that uses wakelocks to keep your task alive and running https://github.com/commonsguy/cwac-wakeful .
Also, if your whole app process is getting killed, you may want to look into persisting the task queue to disk, using something like Tape, from Square
I think the way to go is loading urls in an array, then starting an AsyncTask, returning a boolean to onPostExecute indicating if the operation has success or not. then, keeping a global int index, you can run the AsyncTask with the next index if success, or the same index otherwise. Here is a pseudocode
private int index=0;
//this array must be loaded with urls
private ArrayList<String> urlsArray;
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
class MyDownloaderAsyncTask extends AsyncTask<String,String,Boolean>{
#Override
doInBackground(String... input){
//downlaod my data is the function which download data and return a boolean
return downloadMyData();
}
#Override
onPostExecute(Boolean result){
if(result)
new MyDownloaderAsyncTask().execute(urlsArray.get(++index));
else
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
}
}
hope this help
I have just completed an open source library that can do exactly what you need. Using droidQuery, you can do something like this:
$.ajax(new AjaxOptions().url("http://www.example.com")
.type("GET")
.dataType("JSON")
.context(this)
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
//since dataType is JSON, params[0] is a JSONObject
JSONObject obj = (JSONObject) params[0];
//TODO handle data
//TODO start the next ajax task
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxError error = params[0];
//TODO adjust error.options before retry:
$.ajax(error.request, error.options);
}
}));
You can specify other data types, which will return different object types, such as JSONObject, String, Document, etc.
Similar to #Murtuza Kabul I'd say use a service, but it's a little complicated than that. We have a similar situation related to constant internet access and updates, although ours places greater focus on keeping the service running. I'll try to highlight the main features without drowning you in too much detail (and code is owned by the company ;) )
android.permission.RECEIVE_BOOT_COMPLETED permission and a BroadcastReceiver listening for android.intent.action.BOOT_COMPLETED to poke the service awake.
Don't link the service to the Activity, you want it running all the time. eg we call context.startService(new Intent(context.getApplicationContext(), OurService.class))
The service class is just a simple class which registers and calls an OurServiceHandler (as in our case we fire off repeated checks and the Handler manages the 'ticks')
We have an OurServiceRunnable which is a singleton which is checked and called by the Handler for each test. It protects against overlapping updates. It delegates to an OurServiceWorker to do the actual lifting.
Sounds heavy handed, but you want to ensure that the service is always running, always ticking (via the Handler) but only running a single check at a time. You're also going to run into database issue if you use the standard SqlLite DbHelper paradigm, as you can't open the DB on multiple threads and you definitely want the internet access off the main thread. Our hack was a java.util.concurrent.locks.ReentrantLock protecting access to the DB, but you could probably keep DB access on the UI thread and pass DB operations via the Handler.
Beyond this it's just a matter of keeping the downloads atomic in terms of "get task, download task, complete task" or enabling it to pick up from a failed state eg downloaded OK, attempt to complete.
You should take a look at the volley library :
http://www.javacodegeeks.com/2013/06/android-volley-library-example.html
There is also an interesting video of the author that took place at google io 2013 :
http://www.youtube.com/watch?v=yhv8l9F44qo
Mainly because it eases the process of managing a lot of these fastidious tasks that are connection checking, connection interruption, queue management, retry, resume, etc.
Quoting from the javacodegeeks "Advantages of using Volley :
Volley automatically schedule all network requests. It means that Volley will be taking care of all the network requests your app executes for fetching response or image from web.
Volley provides transparent disk and memory caching.
Volley provides powerful cancellation request API. It means that you can cancel a single request or you can set blocks or scopes of requests to cancel.
Volley provides powerful customization abilities.
Volley provides Debugging and tracing tools"
Update from dennisdrew :
For large file, better use a variant of volley which authorize using another http client implementation. This link gives more details :
The volley article about this modification :
http://ogrelab.ikratko.com/android-volley-examples-samples-and-demos/
The github file detail :
https://github.com/ogrebgr/android_volley_examples/blob/master/src/com/github/volley_examples/toolbox/ExtHttpClientStack.java
public class FetchDataFromDBThread implements Runnable {
/*
* Defines the code to run for this task.
*/
#Override
public void run() {
// Moves the current Thread into the background
android.os.Process
.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
FetchDataFromDB();
}
}
I'm looking for a design pattern or approach for the following scenario. I wish to kick off two separate background threads for data retrieval from different sources. I then want one method (on the UI thread) to be called once both background threads have completed their work. As the data from the two sources must be combined to be useful, I must wait until both have finished retrieving before manipulating the data. How can I achieve this on the Android platform?
Edit: My first version has been bothering me, and I didn't like the necessary added boolean with it, so here's another version. Call it with this from onPostExecute of each added task.
ArrayList<AsyncTask> tasks;
public void doStuffWhenDone(AsyncTask finishedTask)
{
tasks.remove(finishedTask);
if(tasks.size() > 0)
return;
... do stuff
}
I'll keep the older one up also, since they both work, but I think the above is much cleaner. Now to go tidy up one of my earlier projects.
ArrayList<AsyncTask> tasks;
boolean hasBeenDone = false;
public void doStuffWhenDone()
{
for(int i=0;i<tasks.size();i++)
if(hasBeenDone || (tasks.get(i).getStatus() != AsyncTask.Status.FINISHED))
return;
hasBeenDone = true;
... do stuff
}
It's easily extendable to however many tasks you have, and there's no need for a thread to handle the threads. Just call the method at the end of each task. If it's not the last one done, nothing happens.
Edit: Good point, but I don't think it needs to be atomic. Since both AsyncTasks' onPostExecute methods run on the UI thread, they'll be called one after the other.
Use a CountDownLatch, like this:
CountDownLatch barrier = new CountDownLatch(2); // init with count=2
startWorkerThread1(barrier);
startWorkerThread2(barrier);
barrier.await(); // it will wait here until the count is zero
doStuffWithTheResult();
when a worker thread finishes, call barrier.countDown() from it.
You can use AsyncTask and an int to know if both jobs are finished...