I am writing an application that searches a database in "realtime".
i.e. as the user presses letters it updates a search results list.
Since the search can take a while, I need to do the search in background and allow new key presses to re-start a search. So that is a user presses 'a' (and the code starts searching for "a"), then presses 'b' - the code will NOT wait for "a" search to end, then start searching for "ab", but rather STOP the "a" search, and start a new "ab" search.
To do that I decided to do the search in an AsyncTask. Is this a wise decision ?
Now - whenever a keypress is detected, I test to see if I have an AsyncTask running. If I do - I signal it (using a boolean within the AsyncTask) it should stop. Then set a timer to re-test the AsyncTask within 10 mSec, to see if it terminated, and start the new search.
Is this a smart method ? Or is there another approach you would take ?
TIA
First yes, AsyncTask is a good way to do this. The problem I see with your approach is the timer waiting to watch something die. When you invoke the asyncTask hold onto a reference of it. Let it keep state for you so you know if it's out searching or it's has returned. When the user clicks another letter you can tell that asyncTask to cancel. Something like this:
public void onClick() {
if( searchTask != null ) {
searchTask.cancel();
}
searchTask = new SearchTask( MyActivity.this ).execute( textInput.getText() );
}
public class SearchTask extends AsyncTask<String,Integer,List<SearchResult>> {
private boolean canceled = false;
protected onPostExecute( List<SearchResult> results ) {
if( !canceled ) {
activity.handleResults( results );
}
}
public void cancel() {
canceled = true;
}
}
This is safe because onPostExecute() is on the UI thread. And cancel() is only called from the UI thread so there is no thread safety issues, and no need to synchronize. You don't have to watch a thread die. Just let the GC handle cleaning up. Once you drop the reference to the AsyncTask it will just get cleaned up. If your AsyncTask blocks that's ok because it only hangs up the background thread, and when the timeout hits it will resume by calling onPostExecute(). This also keeps your resources to a minimum without using a Timer.
Things to consider about this approach. Sending a new request everytime a new letter is typed can overload your servers because the first few letters are going to produce the largest search results. Either limit the number of results you'll return from the server (say 10-50 results max), or wait until they've entered enough characters to keep results down (say 3). The cons of making the user type more characters is the feedback doesn't kick in until 3 chars. However, the pro is it will dramatically reduce the hits on your server.
Related
Basically I have 2 tabs.
In which first tab contains the data, and the second one contains some summary kind of data based on first tab's data.
In the first tab there is list of events. Whenever the there is an add/update/delete operation on events the summary needs to recalculated. The recalculated summary creates the list of rows in the database. And from those rows the summary tab is displayed.
So the problem is summary calculation takes long amount of time. So it is blocking the UI thread. So I moved the calculations in the thread for smooth UI operations.
Now as summary calculation is running in thread, I don't know when the calculation is complete and now I need to update the summary tab data and showing something while calculation is going on.
The current setup which I have is something like this:
My DatabaseHelper Class:
add() {
...
// Do Add operation
...
reCalculateSummary();
}
remove() {
...
// Do remove operation
...
reCalculateSummary();
}
reCalculateSummary() {
new Thread(new Runnable() {
#Override
public void run() {
...
// calculate summary (may call another method)
...
// Add calculated summary to DB
}
}).start();
}
While the reCalculateSummary() is running, the summary to tab should show loading message.
So How can I achieve this whole situation working?
How can I know if thread has completed its execution? So that I can update summary tab data by retrieving new db values of summary data.
So here is some confusing situation. Please feel free to ask if you have any doubts in understanding the situation.
Thanks in advance!
Use an event bus, so you can update the UI, and avoid the limitation on AsyncTasks.
You can create the event "recalculateSummary", and just before job start (think of it as onPreExecute), update the UI with something that shows the user that the information on screen is not up-to-date, and update results when job is done.
Examples on event buses are Otto, EventBus, AutoBus ...
You can use an AsyncTask.
Do the processing in the doInBackground(..) method, and update the UI inside onPostExcecute(..) method
I have a method playSoE() that performs an operation on each view and updates the ArrayAdapter and thus GridView after each operation. I want to do is have the code wait for 1 second after the update is done, and then perform the operation on the next view. For example:
public class MainActivity extends Activity{
public void playSoE(){
for(int i = 0; i < primesLE; i++) //iterates to each view
mAdapter.setPositionColor(index, 0xffff0000 + 0x100 * index); //operation performed on view
mAdapter.notifyDataSetChanged(); //updates adapter/GridView
//Code that waits for one second here
}
}
I have tried many threading APIs but none of them seem to work, they've either froze up the application for primesLE seconds and shown all the operations at the end, skip the second wait and just performed all the operations at once, or gotten an Exception related to concurrency.
Assuming the update itself is quick, you should not be creating additional threads at all. Create a Handler and use postDelayed(...) to time your updates in the UI thread.
You may have to take a look at AsyncTask.
Put the wait code at the doInBackground() and then the following that affects the visual on the onPostExecute()
All you do on doInBackground() will not freeze your application.
I need to be able to cancel tasks involving web requests.
but I got some issues of memory management and exception handling when something fail.
For example:
I want to create a text edit for searching apps in user device.
so whenever user end a key, I want to clear current search task, and restart search.
The problem I got is in android 4.4, when trying to load the label of the app (to get it's name) I get an exception.
Also of I try to search contacts I'm getting an invlalid uri, fo rcontact photo.
I don't want any help dealing with this errors, I want a solution that will help me ignore this erros (try catach dont work) currently the entire ui get's stuck and app crash.
I'm using the executors service and call cancel when user gives me an input. but it's not enough.
Any advice will be appreciated, thanks.
if you're using AsyncTask i would like to suggest you to make it like this
AsyncTask<Void, Void, Void> a = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
return null;
}
};
a.execute();
// at some point you want to cancel just use
a.cancel(true);
You can even put tasks together in List or array and loop to cancel it whenever you want.
You can try like this: what you want is getting result in background by network and show result in view ,you can Register a Listener to one task,. you can callback method of listener to use show result in view if it get the results in background ,if you do not need the result of current task and want satrt the next task ,you can only remove listener of current task,so the view will not reload
This is my idea ,I am so sorry for my bad english , if you do not see ,you can send message to me, and my email is bjltxsp#gmail.com
I need to write an android application like a book. I have approximately 100 images and i need to show them with back, forward and another buttons.
I tried to create an xml-layout for each image and made images to layout's background.
While running application, if i press buttons fast, program crashes during switching xml-layout.. If i decrease image sizes my problem decreases also. Unfortunately, i need another solution in order to solve it because i cannot use smaller image-size but i have crash problem still.
Have one layout, with an ImageView in it. Then keep changing the source image for the image view whenever you need to cycle to the next or previous image.
Part of the problem is that clicking a UI button returns immediately / queues clicks, even though the action associated with that click has not yet completed. For reasons beyond the scope of this response, its worth noting that simply deactivating the button while "doing work" is ineffective. There are a couple solutions to this kind of problem: One is to use a boolean flag that gets set only after the underlying "work" has completed. Then within the button action handler, you ignore button clicks that occur before the flag is reset:
/**
* Button presses are ignored unless idle.
*/
private void onMyButtonClicked() {
if(idle) {
doWork();
}
}
/**
* Does some work and then restores idle state when finished.
*/
private void doWork() {
idle = false;
// maybe you spin off a worker thread or something else.
// the important thing is that either in that thread's run() or maybe just in the body of
// this doWork() method, you:
idle = true;
}
Another generic option is to filter using time; ie. you set a limit where the max frequency of button presses is 1hz:
/**
* Determines whether or not a button press should be acted upon. Note that this method
* can be used within any interactive widget's onAction method, not just buttons. This kind of
* filtering is necessary due to the way that Android caches button clicks before processing them.
* See http://code.google.com/p/android/issues/detail?id=20073
* #param timestamp timestamp of the button press in question
* #return True if the timing of this button press falls within the specified threshold
*/
public static synchronized boolean validateButtonPress(long timestamp) {
long delta = timestamp - lastButtonPress;
lastButtonPress = timestamp;
return delta > BUTTON_PRESS_THRESHOLD_MS;
}
Then you'd do something like this:
private void onMyButtonClicked() {
if(validateButtonPress(System.currentTimeMillis())) {
doWork();
}
}
This last solution is admittedly non deterministic, but if you consider that users almost never intentionally click button more than 1-2 times a second on a mobile device, its not so bad.
My application is processing data (which involves lot's of calculation, creation of arrays, clearing of those arrays) is it possible to resume from the place it left the calculation when the application resumes ?
While the calculation is going on I am showing a progress bar which cannot be cancelled using the back button, but in-case the user clicks the home button I do not want my calculation to be lost but instant stay exactly at the point till the application is run again and display the final results.
Thanks
====== Edit ======
I call ProcessingAsync().execute() in the onCreate method
The content of doInBackGround of my ProcesingAsync class is given below: (Using spinner and not horizontal progress bar to show the activity is going on)
#Override
protected String doInBackground(String... aurl) {
recordedDataFile = new File(Environment.getExternalStorageDirectory().getPath(), "Machine_Health_Monitoring/Temporary_Files/Fault" + faultNumber + FORMAT_WAV);
runThisCalculationMethod(2, recordedDataFile);
// showWaitingMessage becomes false after the runThisCalculationMethod() is completed
while(showWaitingMessage){
}
return null;
}
You can create a marker (that shows in which part of the calculations you're at) and a partial-result and save it to a file. When you try resuming you'll first look in the file (if it exists) and continue from the last saved point. After you've finished all your calculations and displayed the results - make sure to delete the file.