0

This is a common question, and I have read up on the various ways of handling it, but each on seems to fall short for what I am trying to do, which is essentially be a good OO-Citizen.

I have an Activity that invokes a CommunicationManager, which basically polls a TCP socket for data. When the CommunicationManager receives data, it throws a custom event (containing the string it just fetched), which is handled by the Activity. I am doing this, A) because other classes will depend on that data, not just the Activity, and B) because the polling is asynchronous, and should fire an event when it receives results.

My problem lies in that I need to surface those results into a TextView on the UI. I have the polling mechanism all set up, it fires every 1000ms, and invokes the event handler on the Activity. However, the UI never updates.

Assumedly this is a thread issue and the UI thread is not the one getting the change to the TextView, but how do I do this?? I have tried using a Handler, but am not sure where to put it, and when I did get it compiling it never updated the UI.

This seems relatively trivial if everything was done within the Activity, but adding in this other class (CommunicationManager) and the event is making it very confusing for me.

Here is what I have so far:

ACTIVITY (polling is invoked by clicking a button on the UI):

public void onClick(View v) {
    if (v.getId() == R.id.testUDPBtn) {
        statusText.setText("");

        commMgr = new CommunicationManager();
        commMgr.addEventListener(this);

        MediaPositionPollThread poller = new MediaPositionPollThread(commMgr);
        poller.startPolling();
    }
}

@Override
public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {
    statusText.append(e.userData);
}

THREAD:

class MediaPositionPollThread extends Thread {
    private CommunicationManager commManager;
    private static final String TAG = "MediaPositionPollThread";
    private boolean isPolling = false;

    public MediaPositionPollThread(CommunicationManager cm) {
        commManager = cm;
    }

    public void startPolling() {
        isPolling = true;
        this.run();
    }

    public void stopPolling() {
        isPolling = false;
    }

    @Override
    public void run() {
        while (isPolling) {
            try {
                commManager.getCurrentMediaPosition();
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                Log.d(TAG, "EXCEPTION: " + e.getMessage());
            }
        }
    }
}

COMMUNUCATION MANAGER:

public void getCurrentMediaPosition() {
    PrintWriter outStream;
    BufferedReader inStream;
    String resultString = "";

    try {
        outStream = new PrintWriter(tcpSocket.getOutputStream(), true);
        outStream.println("GET?current_pts");

        inStream = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
        resultString = inStream.readLine();

        fireEventWithData(resultString);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public synchronized void addEventListener(MediaPositionFoundEventListener listener)  {
    _listeners.add(listener);
}

public synchronized void removeEventListener(MediaPositionFoundEventListener listener)   {
    _listeners.remove(listener);
}

private synchronized void fireEventWithData(String outputString) {
    MediaPositionFoundEvent evt = new MediaPositionFoundEvent(this);
    evt.userData = outputString;

    Iterator<MediaPositionFoundEventListener> i = _listeners.iterator();
    while(i.hasNext()) {
        ((MediaPositionFoundEventListener) i.next()).handleMediaPositionFoundEvent(evt);
    }
}

So I have the Activity making a thread that gets executed every second, calling CommunicationManager >> getCurrentMediaPosition, which in turn fires the MediaPositionFoundEvent, which is handled by the Activity and updates the TextView (statusText) on the screen.

Everything works except the screen not updating. I have tried runOnUiThread, and a Handler, but am obviously not getting it right.

Thanks in advance for any insight or solutions!

Raconteur
  • 1,381
  • 1
  • 15
  • 29

2 Answers2

2

In your Activity class, add a private Handler _handler, Initialize it in your onCreate Activity method,

and change your handleMediaPositionFoundEvent method to

@Override    public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {  
          _handler.post(new Runnable(){  
             public void run(){  
               statusText.append(e.userData);  
           });  
          }  
        }
Simon Dorociak
  • 33,374
  • 10
  • 68
  • 106
VinceFR
  • 2,551
  • 1
  • 21
  • 27
  • Hey Vince, first off, you are a God among men for answering so quickly, thank you. However, this is what I had tried, and while the code enters the handleMediaPositionFoundEvent method, it never gets into the run method within... meaning if I break on handler.post it breaks, but a breakpoint on statusText.append is never hit. The UI does not update either. – Raconteur Jun 06 '12 at 21:55
  • Two other things I notice - first I had to specify that MediaPositionFoundEvent e was final to get it to compile, and also the first line of the button click handler that kicks everything off sets the statusText to "", but that never happens either, and that is called from the main thread. Could that be a clue? – Raconteur Jun 06 '12 at 21:57
  • No problem if you had add final to your MediaPositionFoundEvent e. Its seems that your MediaPositionPollThread is blocking your UI Thread...replace this.run() by this.start() in your MediaPositionPollThread class – VinceFR Jun 06 '12 at 21:59
1

It looks like your blocking the UI thread with your custom Thread. Please update this method to call start() vs run().

public void startPolling() {
    isPolling = true;
    this.start();
}
HandlerExploit
  • 8,131
  • 4
  • 31
  • 50
  • Thanks a MILLION HE! This proved to be the thing, however, it also required VinceFR's code as well. You all ROCK!!! – Raconteur Jun 06 '12 at 22:02