How do I ensure code is or is not executed on the UI thread in an Android MapActivity project?
I am developing an Android map-based application, but I have experienced some stability issues and my research has led me to believe I need to ensure that screen updates are carried out on the UI thread.
My app has data coming in from a GPS listener (which I would like to configure as a separate thread) and a UDP listener (which is already a separate thread), and it has the usual set of android software life cycle methods, but I must be inexperienced or something, because I have no idea where to put code that updates the map overlays
(a) on the UI thread,
(b) in a recurring manner.
I have no preference between a polling or an event-driven process (timer-based perhaps, or the arrival of incoming data), so suggestions of either type will be gratefully accepted.
Anyone got any ideas??
Thanks,
R.
Read this post on painless threading, particularly the Activity.runOnUIThread
You can also look at this Handling Expensive Operations in UI Thread. In your case you can do the following:
public class MyActivity extends Activity {
[ . . . ]
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setup location listener
[ . . . ]
startNonUIThread();
}
protected void startNonUIThread() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
try{
while(true){
sleep(1000);
mHandler.post(mUpdateResults);
}
}catch(InterruptedException e){
//blah blah
}
}
};
t.start();
}
private void updateResultsInUi() {
// Back in the UI thread -- update UI elements based on data from locationlistener
//get listener location
//use the location to update the map
[ . . . ]
}
}
The android location service is a module that runs in the background so you do not need to seperate it in another thread.
However I would not recommend you to use java thread class or runnable interface at all, use async task instead which performs all the thread management for you. Have a look at the android developers blog, Painless Threading.
To update your UI thread on location updates you can use update handlers. Everytime there is GPS data avialable a message is transmitted to the update handler in you main ui thread.
E.g.
public void onLocationChanged(Location location) {
location = this.lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
try {
this.mLongitude = location.getLongitude();
this.mLatitude = location.getLatitude();
Message msg = Message.obtain();
msg.what = UPDATE_LOCATION;
this.SystemService.myViewUpdateHandler.sendMessage(msg);
} catch (NullPointerException e) {
Log.i("Null pointer exception " + mLongitude + "," + mLatitude, null);
}
}
And in your main activity class:
Handler myViewUpdateHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_LOCATION:
//do something
}
super.handleMessage(msg);
}
};
Related
The following code is what I'm using currently, but there is an issue that the Toast is being shown, so it probably is in the UI thread isn't it? I do not want the run() function to run on the UI thread as I will probably add some heavy downloading there. However, I want to repeatedly execute this code (after every 9000ms) So what must I do, to either make this run off the UI thread, or a solution to my problem. Thank you.
final Handler handler = new Handler();
Thread feedthread = new Thread()
{
#Override
public void run() {
super.run();
Toast.makeText(context, "UI", Toast.LENGTH_SHORT).show();
handler.postDelayed(this, 9000);
}
};
handler.postDelayed(feedthread, 9000);
Please do not suggest AsyncTask to me unless there is a way to repeat the code without using a while loop wasting resources or setting the thread to sleep. I would like answers to what I asked, and I do not want to run the code on the UI thread.
You need to call the runOnUiThread method to show the Toast
final Handler handler = new Handler();
Thread feedthread = new Thread()
{
#Override
public void run() {
super.run();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "UI", Toast.LENGTH_SHORT).show();
}
});
handler.postDelayed(this, 9000);
}
};
handler.postDelayed(feedthread, 9000);
You want to use the AsyncTask class. Here is an example to show how it works:
// Async Task Class
private class MyTask extends AsyncTask<String, String, String> {
// (Optional) Runs on the UI thread before the background task starts
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do some UI stuff if needed
}
// Runs on a background thread
#Override
protected String doInBackground(String... param) {
String url = param[0];
// Do something with the param, like kick off a download
// You can also use publishProgress() here if desired at regular intervals
/*while (isDownloading) {
publishProgress("" + progress);
}*/
return null;
}
// (Optional) Runs on the UI thread periodically during the background task via publishProgress()
protected void onProgressUpdate(String... progress) {
// Update UI to show progress
/* prgDialog.setProgress(Integer.parseInt(progress[0])); */
}
// (Optional) Runs on the UI thread after the background task completes
#Override
protected void onPostExecute(String file_url) {
// Do some UI stuff to show completion of the task (if needed)
}
}
You can run your task like this:
String url = getInternetUrl();
new MyTask().execute(url);
Java Thread
new Thread(new Runnable(){
private boolean stopped = false;
#Override
public void run(){
while(!stopped) {
// Do, do, do...
try {
Thread.Sleep(9000);
} catch(Exception e){}
}
}
}).start();
Android Handler
Also you can use Android handler class to run a code periodically. This requires you to have a looper-prepared thread to attach the handler to. Basically, a looper-prepared thread is assign a queue and every message posted to this thread will be queued and processed one by one in a queue manner.
This approach has a difference with the former one and is that if your do a lot of work in that background thread so that takes some time, then subsequent queued messages will be processed quicker than the interval (in this case, 9 seconds). Because looper-enabled threads immediately process the next queued message, once they are done with the previous one.
Find More Info Here
Note: You shouldn't [and can't] use this approach as an alternative to Service. This newly created thread does need an underlying component (either Activity or Service) to keep it alive.
I have a thread where I need to periodically perform some checks, get files from the web, and send messages to the main UI thread. I even need to use UI thread parameters (like the map visible area) on each loop of the worker thread. So I suppose that i need to implement bidirectional communication between UIthread and workerThread.
Another problem is that I need to save the identifier of each marker added to the map. I want to save the result of map.addMarker inside my custom array stored in my worker thread. this means that from the uithread, where i update the map, i should tell the workerThread to update the array of markers..
This is a sample of my actual worker thread:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
My actual problem is that when the UI thread ends processing the message received from the worker thread i should perform an action on the worker thread.
I thought 2 solutions:
1)wait on the worker thread till the message has been processed by the UI thread
2)process the message on the UI thread and then send a message to the worker thread.
I don't know how to do the solution1, so i tried the solution2. I tried adding a looper to my worker thread (RUN sub), this way:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// Act on the message received from my UI thread doing my stuff
}
};
Looper.loop();
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
The problem is that after the Looper.loop() no line of code is executed. I read that this is normal. I read many articles but I didn't understand how should I allow the execution of my while loop, and simultaneously process messages coming from my UI thread.
I hope the problem is clear. Suggest me the best solution.
don't do this:
while(true){
sleep(2000);
it's awfully bad on so many levels. if you need some background processing, use AsyncTasks, if you need a repeating event, use:
private Handler mHandler = new Handler();
private Runnable mSomeTask = new Runnable() {
public void run() {
doSomething();
}
};
and then somewhere in the code:
mHandler.postDelayed(mSomeTask, 100);
this will make your program work faster, jam less resources and basically be a better Android citizen.
I realize this is a very old question, but for periodic task scheduling, use this code:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> periodicTask = scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// do some magic stuff here
// note however, that you're running in background!
Log.d("PeriodicTask", "Doing something....");
}
}, 0 /* initial delay */, 10 /* start every 10 seconds */, TimeUnit.SECONDS);
and when you need to stop the periodic task, just issue
periodicTask.cancel(true);
I have one function which queries a network server with a few "ping pongs" back and forth, and have written a custom handler to handle the message communication between my main UI thread and the communication thread (I was using AsyncTask for this, but as the program got more complex, I have decided to remove the communication code to its own class outside of the main activity).
Triggering a single instance of this thread communication from onCreate works perfectly, no problem.
I want this query to run on a regular timed basis -- in the background -- for the entire time the app is in use, so I've set up another thread called pollTimer, which I'm trying to use to call the OTHER thread at a regularly scheduled basis.
Obviously, it's crashing, or I wouldn't be posting this.
Is there a way to get a thread within a thread? Or put differently, trigger a thread from another thread?
Timer pollTimer = new Timer();
private void startPollTimer(){
pollTimer.scheduleAtFixedRate(new TimerTask(){
public void run(){
Log.d(TAG,"timer dinged");
//if the following is commented out, this "dings" every 6 seconds.
//if its not commented out, it crashes
threadedPoll();
}
}, 3120, 6000);
}
private void threadedPoll() {
testThread(asciiQueries,WorkerThreadRunnable.typeLogin);
}
edit: it would probably help to include the "testThread" function, which works by itself when called from onCreate, but does not make it when called from the Timer.
"WorkerThreadRunnable" is the massive chunk of code in its own class that has replaced the mess of having AsyncTask handle it inside the main activity.
private Handler runStatHandler = null;
Thread workerThread = null;
private void testThread(String[] threadCommands, int commandType){
if(runStatHandler == null){
runStatHandler = new ReportStatusHandler(this);
if(commandType == WorkerThreadRunnable.typeLogin){
workerThread = new Thread(new WorkerThreadRunnable(runStatHandler,threadCommands, WorkerThreadRunnable.typeLogin));
}
workerThread.start();
return;
}
//thread is already there
if(workerThread.getState() != Thread.State.TERMINATED){
Log.d(TAG,"thread is new or alive, but not terminated");
}else{
Log.d(TAG, "thread is likely deaad, starting now");
//there's no way to resurrect a dead thread
workerThread = new Thread(new WorkerThreadRunnable(runStatHandler));
workerThread.start();
}
}
You seem to be well on the way already - the nice thing about handlers, though, is that they aren't limited to the UI thread - so if you have a Handler declared by one thread, you can set it up to take asynchronous instructions from another thread
mWorkerThread = new WorkerThread()
private class WorkerThread extends Thread {
private Handler mHandler;
#Override
public void run() {
mHandler = new Handler(); // we do this here to ensure that
// the handler runs on this thread
}
public void doStuff() {
mHandler.post(new Runnable() {
#Override
public void run() {
// do stuff asynchronously
}
}
}
}
Hopefully that helps... if I'm totally off base on your problem let me know
Wots wrong with a sleep() loop? Why do you have pagefuls of complex, dodgy code when you could just loop in one thread?
I created a class extending Thread to retrieve user location through LocationManager in a non-ui thread. I implemented this as a thread because it has to be started on request and do its work just for a limited time.
By the way, I had to add a Looper object in the thread, to be able to create the handler for the LocationManager (onLocationChanged).
This is the code:
public class UserLocationThread extends Thread implements LocationListener {
//...
public void run() {
try {
Looper.prepare();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
Looper.loop();
Looper.myLooper().quit();
} catch (Exception e) {
//...
}
}
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
//...
handler.sendMessage(msg); //this is the handler for communication with father thread
}
//...}
I would like the thread to start, receive the user location data (in this case just one time), send the data to the main thread via a message to the handler, and then die.
The problem is that in my case the thread does not die anymore, once the run method ended (that should be fine, because otherwise onLocationChanged would not receive the new locations).
But in this way, assuming that thread's stop and suspend methods are deprecated, what would be a good way, in this case at least, to make a thread with a looper die?
Thanks in advance ;)
You can explicitly quit from Looper's loop using Handler:
private Handler mUserLocationHandler = null;
private Handler handler = null;
public class UserLocationThread extends Thread implements LocationListener {
public void run() {
try {
Looper.prepare();
mUserLocationHandler = new Handler();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
Looper.loop();
} catch (Exception e) {
//...
}
}
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
//...
handler.sendMessage(msg);
if(mUserLocationHandler != null){
mUserLocationHandler.getLooper().quit();
}
}
"I implemented this as a tread because it has to be started on request and do its work just for a limited time."
This sounds like a perfect reason to simply reuse the main looper. There's no need to spawn a new Thread here. If you're doing blocking work (network I/O, etc) in onLocationChanged(), at that point you could spin up an ASyncTask.
Implement LocationListener on your Activity/Service or whatever and let it use the main looper by default.
Spawning a new thread, setting it to loop, and then immediately quitting is unnecessary.
IntentService is good for do this job.
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Looper().quit(); is good, and according to specification:
Causes the loop() method to terminate without processing any more messages in the message queue.
But, if you have a task that already is under processing, and you want to stop it too, you can acquire working thread and cause it to interrupt:
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
handler.sendMessage(msg); //this is the handler for communication with father thread
if(mUserLocationHandler != null){
mUserLocationHandler.getLooper().quit();
mUserLocationHandler.getLooper().getThread().interrupt(); // <-- here
}
}
This works fine with most IO, and thread locking/waiting.
Extend the AsyncTask class. It does all the threading and handling for you automatically.
In my OnCreate method I have created a thread that listens to incoming message!
In OnCreate() {
//Some code
myThread = new Thread() {
#Override
public void run() {
receiveMyMessages();
}
};
myThread.start();
// Some code related to sending out by pressing button etc.
}
Then, receiveMyMessage() functions…
Public void receiveMyMessage()
{
//Receive the message and put it in String str;
str = receivedAllTheMessage();
// << here I want to be able to update this str to a textView. But, How?
}
I checked this article but it did not work for me, no luck!
Any updates to the UI in an Android application must happen in the UI thread. If you spawn a thread to do work in the background you must marshal the results back to the UI thread before you touch a View. You can use the Handler class to perform the marshaling:
public class TestActivity extends Activity {
// Handler gets created on the UI-thread
private Handler mHandler = new Handler();
// This gets executed in a non-UI thread:
public void receiveMyMessage() {
final String str = receivedAllTheMessage();
mHandler.post(new Runnable() {
#Override
public void run() {
// This gets executed on the UI thread so it can safely modify Views
mTextView.setText(str);
}
});
}
The AsyncTask class simplifies a lot of the details for you and is also something you could look into. For example, I believe it provides you with a thread pool to help mitigate some of the cost associated with spawning a new thread each time you want to do background work.
Android supports message-passing concurrency using handlers and sendMessage(msg). (It is also possible to use handlers for shared-memory concurrency.) One tip is to call thread.setDaemon(true) if you wish the thread to die when the app dies. The other tip is to have only one handler and use message.what and a switch statement in the message handler to route messages.
Code and Code