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);
Related
My question is very simple, what is the best approach to work with Parse using the local store at the time I want to query the saved objects.
Is it better to trigger several queries to the local store directly on the main thread and avoid nesting a lot of anonymous classes or using a background thread?
It's important thing to notice is that this method is going to be called very frequently and the pattern will be repeated in several places with different queries. I'm evaluating both efficiency and code quality in readability. These methods will be called synchronously so we can assume the data will be consistent at any time.
As the objects are being saved locally I would expect the queries to be very fast in response. Here's a rough sample of how the code would look like in both cases.
Option one:
public void processBatches() {
ParseQuery<Batch> batchQuery = Batch.getQuery();
int batchCount = batchQuery.fromLocalDatastore().count();
List<Batch> batches = batchQuery.fromLocalDatastore().find();
for(Batch b : batches) {
// do whatever I need to do
}
}
Option two:
public void processBatches() {
ParseQuery<Batch> batchQuery = Batch.getQuery();
int batchCount = batchQuery.fromLocalDatastore().countInBackground(new CountCallback() {
#Override
public void done(int i, ParseException e) {
if (i > 0) {
batchQuery.findInBackground(new FindCallback<Batch>() {
#Override
public void done(List<Batch> list, ParseException e) {
for (Batch batch : list) {
// do whatever I need to do
}
}
});
}
}
});
}
Well since in option one you are blocking the UI thread, there could be a delay in the user's ability to interact with your application. This is not a very good option since even if it is for just a moment, users don't want to be waiting unless they know operations are happening. But, if you know that at any time there will be little to no delay, go ahead and do it.
Nevertheless, I argue that option two is going to be the best option. This is because, in general, all network operations should be performed in the background. Although in your case you are performing local datastore queries, suppose a user has gone to their application task manager and cleared the data (very rare this will happen) what happens now when you perform the find from local data store and processing of Batch objects? Well, the app crashes. Again, this is not a very good option for the usability for your application.
Choose the second option, and allow an AsyncThread to run the find() and count() query operations to the network if there is nothing found from local data store queries. Also, from the Parse documentation for find:
public Task<List<T>> findInBackground()
Retrieves a list of ParseObjects that satisfy this query from the source in a background thread.
This is preferable to using ParseQuery.find(), unless your code is already running in a background thread.
Returns:
A Task that will be resolved when the find has completed.
Parse's creators prefers that the users of their API use a background thread to perform operations.
It really depends.
Is the user triggering the update? If so then do it on the main thread because you don't want them waiting
If not, then is the data access a result of fetching data from the web (and hence you should already be on a background thread) so could probably just remain on the background thread
Also what happens in "// do whatever I need to do"? Is it an update to the UI or more background processing?
I am using this following code for getting all songs stored in the sdcard.
https://stackoverflow.com/a/12227047/2714061
Well why does this code take so long to return this list of songs.
I have included this code in a function which is called from the oncreate method in my player's playlist.
This is what happens.
1: When the application runs is executed for the first time on my android ph, the playlist has nothing to show, and hence is seen empty.
2: Well after for instance-> 30sec when I again call for the playlist it returns instantly all the songs.
Hence, giving the feel as though this thing takes time to execute?
Why does this happen?
How about using an asynchronous task, reading a file or downloading something, takes time that requires the user to wait, you must think of using an Asynchronous task for this purpose,
1: From the developer reference we have :
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. http://developer.android.com/reference/android/os/AsyncTask.html
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
2: So you may include an Async task class as:
class DoBackgroundTask extends AsyncTask<URL, Void, ArrayList> {
/*
URL is the file directory or URL to be fetched, remember we can pass an array of URLs,
Void is simple void for the progress parameter, you may change it to Integer or Double if you also want to do something on progress,
Arraylist is the type of object returned by doInBackground() method.
*/
#Override
protected ArrayList doInBackground(URL... url) {
//Do your background work here
//i.e. fetch your file list here
return fileList; // return your fileList as an ArrayList
}
protected void onPostExecute(ArrayList result) {
//Do updates on GUI here
//i.e. fetch your file list from result and show on GUI
}
#Override
protected void onProgressUpdate(Integer... values) {
// Do something on progress update
}
}
//Meanwhile, you may show a progressbar while the files load, or are fetched.
This AsyncTask can be called from you onCreate method by calling its execute method and passing the arguments to it:
new DoBackgroundTask().execute(URL);
3: And at last, there is also a very nice tutorial about AsyncTasks here, http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
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 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
Hey, I have an application which logs onto a few sites using defaulthttpclient and I've found I'm going to need to use the AsyncTask as the requests hold up the UI thread. In my code, I create an instance of a state class i.e. State state = new O2State(); with different states for different sites.
I then call state.logon(String username, String password); which returns a string containing details of the result so:
String result = state.logon(username, password);
I've been trying to implement asynctasks to run this code in another thread and return the string back to the UI thread on completion. The idea is I will display a progress dialog, run the thread, and on complete, will display a dialog with the result.
I've been looking at this example:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
Where I'm stuck is:
I don't think I'll need any arguments, but doinbackground seems to require a list of parameters. I'm also unfamiliar with this time of method argument declaration.
Secondly:
I'm not sure how to return the resulting string when the thread is finished executing. Should I just create a "DoThisWhenTheThreadIsFinished(String result)" and call this from onPostExecute?
Anyway, I hope this isn't too confusing to read and I'd really appreciate any help you can offer.
Thanks
Where you don't need parameters just specify the type (e.g. String) and ignore it, or you could use the Void class (note the capital V).
What you suggest for how to return control back to the UI thread to reflect the update is a good approach. i.e. in onPostExecute() call a method on the activity to update the UI.
As a general rule if any operations will take more than a couple of hundred milliseconds, use a separate thread. You may also want to use a rotating progress indicator to show the app is doing something.
(when people answer your questions, always rate the ones you like, and pick one as the "best" answer. you get points doing this, and it helps others later).