views:

64

answers:

3

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.

A: 

Read this post on painless threading, particularly the Activity.runOnUIThread

I82Much
Thank you to everybody! ArtWorkAD: Thanks for the heads up about the separate thread idea. I started wondering about that soon after posting the original question.
Rich
Dang, I hit the return key again!!! I'm sure there are better methods (just from reading the responses on this page), but I went with a Handler and Runnable and used postDelayed() to call my overlay updating code every 100 milliseconds. It's not perfect, but does seem to be working. I'll work on the ideas here as soon as reasonable.
Rich
Sadly, I lack sufficient rep to give you an Up vote...
Rich
You can click the checkbox and accept this as an answer..
I82Much
A: 

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 
    [ . . . ]
}

}

contador
A: 

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);
        }
    };
ArtWorkAD
Thanks, ArtWork, for the heads up about the separate thread idea. I started wondering about that soon after posting the original question. AND I put this in the wrong block the 1st time. Gah!!
Rich
you're welcome. But keep in mind that you need a update handler to get gps data. I think there is no way round. I did a lot of research on that topic and I always got an nullpointer exception accessing the lng and lat fields. so you need something that informs you about the gps state, wheather there is actually gps data or not. so I did this by sending a message from the gps instance.
ArtWorkAD
Not sure what you mean by "GPS instance" (I'm an engineer and not really a programmer), but I set up my GPS listener as an interface with the callback GpsReadDone (lat, long, time, dist), called by onLocationChanged(). Most of the tasks performed by my listener can be executed directly, but for screen updates I use: runOnUiThread (Runnable doScreenUpdates). Using postDelayed() DID work, but I was unhappy with the un-synchronized nature of the implementation. I'm sure it would be cooler yet to implement an async task, but it seems unnecessary (and daunting) now.
Rich