Killing threads - android

I've created a class which is an extension of Thread. This class hits a web service and throws some data on screen. I don't care about persisting this data (the screen displays search results).
Currently, the user simply types into an EditText and clicks a search button. I'd like to take away the search button and implement something similar to Google's Instant Search where, as you type, the search results get updated.
This means, as the user types, the search parameters change. I want to be able to kill the currently running thread (if one is currently running) and spawn a new one with the new search string. How can this be achieved? Can I do it with Thread or will I need to use a new object?

This is more difficult than simply killing a thread. You can call interrupt() on the thread, but the thread will have to check its interrupt status periodically and self-terminate.
Secondly, you will not want to start a thread immediately on a user typing. You will quickly overwhelm the system with thread spawning. Implement a wait period of 100-200 milliseconds before doing the search so that you can be reasonably sure the user is done typing. Google's server can handle the load, but the handset won't be able to.
EDIT: to expand on my first point, threads can be difficult to cancel. In this case the event dispatch thread will need to somehow tell the running thread it needs to stop. You can use the interrupt facility built into threads, but it tends to be touchy as pointed out by this article. Instead, I would simply have a boolean variable that can be set to cancelled by some outside thread. The trick (like shown in that link) will be that you will need to periodically check if the thread has been cancelled, and if so you will need to manually abort.
The next problem you will run into is if a web call has already been made to some outside server. It will block in that thread until it comes back and the thread will not be able to kill itself. This could take several seconds.
So let's play this out - what if a user types a character, and your timeout period expires for whatever reason and a web call is made, then the user types another character where the timeout period expires so another web call is made? If your web calls take 5 seconds, then the first thread will continue to run, even if the event dispatch thread cancels it, for at least 5 seconds. You now have two threads making web calls.
Now expand that. What if a user does this and makes 4 or 5 threads? This is where you overwhelm the resources of your handset. I am not telling you not to pursue this, just trying to point out the potential problems that come with the territory.

Use the AutoCompleteTextView widget. prefetch your search hints from your web service to load them into the autocomplete array and set its adapter. optionally use a custom cursor adapter depending on how complex your hints are.
something like:
AutoCompleteTextView inputSearch;
String[] autocompleteArray = new String[size of prefetched items];
//fill autocompleteArray with webservice data
inputSearch = (AutoCompleteTextView)findViewById(R.id.inputSearch);
searchAdapter = new ArrayAdapter<String>(context, R.layout.autcomplete_dropdown, autocompleteArray);
inputSearch.setAdapter(searchAdapter);
R.layout.autocomplete_dropdown could look something like:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/name"
android:singleLine="false"
android:textSize="15sp"
android:paddingLeft="3dip"
android:paddingRight="3dip"
android:paddingTop="15dip"
android:paddingBottom="15dip"
android:textColor="#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
do your searching in the app, how large is the content you will be searching? pre-load all the data in sqlite and check for updated data from the web every so often perhaps?
otherwise i'd say you should limit the amount of times your app tries to start a thread. setup some sort of timer that will:
see if...
a thread is already working
the input has changed since the last
time or has a non-empty search value
the user is even on the search
screen
if everything is OK, start up a thread to get results
just a thought, haven't tried this

Thread creating is very consuming operation. Thus I would recommend have one thread which will subsequently call webservices with new search strings.

What you mean is Auto Complete. I don't think you need to start a couple of threads to handle that. Work with android Auto Complete and use AutoCompleteTextView.
Furthermore it is not recommended to use threads by subclassing java thread or implementing the interface. You can use AsyncTask to perform time consuming operations in the background.

Related

Can you indicate to Android the time to wait or tell it that the app is still "active" before displaying "App isn't responding? If so, how?

I'd like to know the code or configuration needed to set that.
In my app, there are some places where I'm willingly make the app to sleep for several seconds, as it's needed for some reasons, with a Thread.sleep(long millis) function.
Problem is that on some Android APIS, at least on 25 and 26, usually that system message pops up in few seconds, confusing the user and maybe even causing the application not to fulfill the needed operations that need to happen while that sleep is happening if the user ends the app, which might cause even malfunctioning of the application.
I'd like to find a way of either forcing Android to wait for a good time like, for example, 1 minute, or to make Android aware that it's not that app isn't responding, that is willingly on a Thread.sleep function.
Is there any way to do that?
I'd like to find a way of either forcing Android to wait for a good time like, for example, 1 minute, or to make Android aware that it's not that app isn't responding, that is willingly on a Thread.sleep function.
TL;DR there is none.
Android apps should at all times be able to yield their position in the foreground to other apps. It's up to the users if they want to wait while some lengthy download is taking place or if they prefer to do something else and come back later.
You can't execute Thread.sleep() on the UI thread for long because this would "freeze the UI".
An example: Users should be able to leave your app by pressing the BACK Button at any time they wish to. If your method is blocking the UI thread, Activity#onBackPressed() can't be executed so the users can't quit.
What can you do? Move the heavy work to another thread (using e.g. AsyncTask or IntentService or some plain worker thread) and show some type of progress indicator to the users if necessary. You can/ should also toggle visibility or enabled state of Buttons etc. if required to avoid clicks which can't be processed at that point in time.
I think you have an implementation problem. The system message, known as ANR (Application Not Responding) occurs when the application cannot respond to user inputs, this may be caused by Ui thread blocking and that may be your case.
To avoid blocking the UI Thread just run your long time operations asynchronously. There are many ways to do that. You could use AsyncTask, AsyncTaskLoader, Thread, RxJava... Here you have some links to help you with that:
https://developer.android.com/training/articles/perf-anr
https://google-developer-training.gitbooks.io/android-developer-fundamentals-course-concepts/content/en/Unit%203/71c_asynctask_and_asynctaskloader_md.html
http://www.vogella.com/tutorials/RxJava/article.html

Is there any point in using Asynctasks for api calls that require a response to proceed?

I feel that the answer to this question is too obvious, but part of me still wants to ask it anyway.
I am creating an Android app that makes several HTTP POST/GET requests using APIs when the app is launched for the first time by the user. All these requests are made by launching Asynctasks within the activity.
For example, there is an activity where athe user has to select an item from a list retrieved from the API. After he selects one, a progress bar is displayed to the user while the app sends the selection to the API to retrieve another list, and in the next activity, the user selects items from this list. Clearly, the user can't go this second list until a response has been received from the server after the app sends it the first list's selection.
In such a case, is there any point in using an Asynctask to send the selection of the first list, since the user is prevented from doing anything (by being shown a progress bar) until a response is received and the next activity is started. Wouldn't it make the code less complex if I just made the API call on the main thread?
I hope this wasn't too confusing.
Thanks
I got your doubt completely. Good question. The root cause of the doubt because you are thinking you don't need to interact with the app till the process completes. But you actually want to. Event the progress bar will freeze if you could do something like it.
Ok, let's just assume you don't even have a ProgressBar. However, handling the different UI components such as Spinners, EditTexts is not the only duty of the main thread. It should define different callbacks in the activity lifecycle. Doing big tasks in main thread will also freeze callbacks like onPause(), onStop() etc. That is why the 'NetworkOnMainThreadException' is being thew.
Basically you cannot call the api on main thread as it will block the UI. Also now Android does not allow it to happen and throws 'NetworkOnMainThread Exception'. Its fine to use Asynctask for any task that takes few seconds and you get the callback in it , which in your case is required before you proceed to next screen.
Best way to do it is by using Networking libraries:
Refer this
https://developer.android.com/training/volley/simple.html
First of all you cannot do netwok call on main thread, it will raise NetworkOnMainThreadException , You can still by pass this exception by adding the couple of following lines in your activity
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
but it is always recommended to perform network operation in background,
else it may cause your app to stop responding, and can result in the OS killing your app for being badly behaved , go through this article once link
Any operation that takes more than a few seconds to perform should be added in a separate thread. All network operations should be performed on AsyncTask or do have a look at RxJava and RxAndroid. To be specific to your operation, any UI Operations during a network call can be performed in onPostExecute. If you're working with thread class then use a Handler.
As others mentioned, if main thread is used for network operation, it would make your app unresponsive.
User may want to start a different flow in your app by starting an activity from menu or action bar whatever is available in your app to start other flow.

How to decide whether to use ASyncTask or not in android?

I have a simple Android UI. When user clicks Button, it takes the user's location and then it goes to 4-5 websites and gets all the events in that hour. Then, according to the user's location, it compares the closest ones, and according to a radius given, it shows the event names in a new screen.
After clicking Button, it will go into another screen and will write something like searching for location or progress dialog, or location identified. After that, it'll show the events to the user. So, should I create 3 activities and 3 screens?
According to this link
how to use method in AsyncTask in android?
He says don't prefer AsyncTask for long network jobs.
I can't use location methods inside AsyncTask. Before executing I should send location as parameter. But again, computeDistance method needed. At post execute method, I can post events to new UI.
But when the user clicks these events, from onClick I can do jobs but I can't find or retrieve info of these events.
I decided to use AsyncTask after commenting somewhere here and someone answered me to use but I can't find that post.
And now i am unsure about to use or not.
I need webconnections, so I don't want to make them in main. So it is good to use AsyncTask for that but is it necessary?
This is what I would recommend:
Use AsyncTask. It will run a background thread and give you a way to display progress in the UI thread as each website is checked. This isn't a "long network job" compared to, say, streaming a video. IMHO, using a Service for something like your operation is just too heavyweight. So start out with an AsyncTask.
Once you have that, however, you will discover your next problem, which is that your web operation might take long enough that if you rotate the device, the Activity will be torn down and recreated in the new orientation. Then when your AsyncTask completes, the Activity it was supposed to call back to is no longer there. Oops, now your user doesn't get their results.
The best solution I have found for that is to use a special fragment to "host" the AsyncTask. This fragment will not create a view and use setRetainInstance(true) to keep the fragment alive during Activity re-creation.
You can read about this novel technique here: Handling Configuration Changes with Fragments
AsyncTask is an abstract class provided by Android which helps us to use the UI thread properly. This class allows us to perform long/background operations and show its result on the UI thread without having to manipulate threads.
Android implements single thread model and whenever an android application is launched, a thread is created. Assuming we are doing network operation on a button click in our application. On button click a request would be made to the server and response will be awaited. Due to single thread model of android, till the time response is awaited our screen is non-responsive. So we should avoid performing long running operations on the UI thread. This includes file and network access.

Android loading string array into activity using background thread

I have an activity where the user enters a value in an EditText and I search a string array that I have defined in a xml file for a match. Each time the user changes the text I look for a match. When I start this activity I load the string array resource.
Should the loading of the array and the match finding occur in a background thread?
From what I understand I can use an AsyncTask which I am familiar with or a IntentService which I have no experience with. Would IntentService be overkill? What is ideal for this operation?
In some cases it is possible to accomplish the same task with either an AsyncTask or a Service however usually one is better suited to a task than the other.
AsyncTasks are designed for once-off time-consuming tasks that cannot be run of the UI thread. A common example is fetching/processing data when a button is pressed.
Services are designed to be continually running in the background. In the example above of fetching data when a button is pressed, you could start a service, let it fetch the data, and then stop it, but this is inefficient. It is far faster to use an AsyncTask that will run once, return the data, and be done.
If you need to be continually doing something in the background, though, a Service is your best bet. Examples of this include playing music, continually checking for new data, etc.
For the most part, Services are for when you want to run code even when your application's Activity isn't open. AsyncTasks are designed to make executing code off of the UI thread incredibly simple.
You should use AutoCompleteTextView and ContentProvider to do your implementation. Save your string array in database and access them by Cursor to popup and show in AutoCompleteTextView. There is an example available in the official document.

What is the correct control flow for getting a one-time fix on the user's location (via GPS)?

I'm looking to find the "correct" way to get a fix on the user's location as a one-time task. At the moment, my execution flow is roughly:
The user presses a button.
The handler (contained in the main Activity code) registers a GPS location listener with the system, set to update as fast as possible, launches an ASyncTask, and finishes.
Pre-execution, the ASyncTask generates a ProgressDialog, effectively blocking any other UI usage.
For it's background task the ASyncTask waits for either a timeout or for a location fix for the GPS.
Post-execution, the ASyncTask either displays some relevant data to the user if a location was found, or displays an error in a toast if it was not. It also de-registers the listener of course.
Now, while this works, there are numerous downsides. Firstly, and quite obviously, all other UI interaction with the app is blocked while a request is being made. This isn't too bad currently, as the app's main function is to perform this task, and there isn't much else to do while it's working - it also stops the user from spamming the button. Additionally, I'm not sure if the post-execution phase of the ASyncTask is really the place to put my location-found logic (it makes an internet call, which is something that itself might be better off inside an ASyncTask?). However, I'm not sure how else to pass back the fact that a location has been found and that the main thread should do something.
I was hoping that someone could inform me as to the "right" way to do this - i.e. is using an ASyncTask like this correct, should there be a Service involved, and how should I deal with the internet-call post-location-found), and perhaps even give some wise words on how in general to deal with the control flow of an app which has to make somewhat "blocking" calls.
I can provide code if needed, might take a bit to get it cut down to a minimum solution.
Blocking calls and blocking UIs are generally to be avoided. See Reto Meier's take on the subject.
Hence, I'd dump the AsyncTask entirely. Disable the Button that the user uses to kick off the fix request. Use a postDelayed() Runnable for your timeout mechanism. And, allow the user to do something (read help, etc.). Use the progress indicator in the title bar to indicate that you're working on getting the location, dismissing the indicator when you get a fix or when your timeout occurs.
(it makes an internet call, which is something that itself might be better off inside an ASyncTask?)
It certainly should not be done on the main application thread. When the location fix comes in, kick off the AsyncTask to fetch the data.

Categories

Resources