0

I'm doing a http call with kSoap within a TimerTask so I can update the data something like every five minutes. After getting the data from a web service I provide them to an interface via the function procecssData(). This works out perfectly for the first time, but although the timer is firing every time the data stays the same. So in fact, my UI is being drawn every five minutes but it always uses the data from the first http call. Does someone have an idea why this might happen? Seems to me that the variables inside the httpCall() function are not being updated.

public class ConnectionThread extends Thread {

SoapObject request;
SoapObject result;
SoapSerializationEnvelope envelope;

String[][] resultArray;
int resultLength;

public ConnectionThread(ConnectionCallback conCallback) {

    callbackObj = conCallback;

    refreshTask = new TimerTask() {
        public void run() {
            httpCall();
        }
    };

    new Timer().schedule(refreshTask, 0, 50000);
}

public void httpCall() {

    request = new SoapObject(serviceNamespace, methodName);
    result = null;

    envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.setOutputSoapObject(request);

    http = new HttpTransport(serviceUrl);

    try {
        http.call(soapAction, envelope);
        result = (SoapObject) envelope.getResponse();
        resultLength = result.getPropertyCount();
    } catch (final InterruptedIOException ex) {
        Dialog.alert("No Internet Connection!");
        _isConnected = false;
    }
    // some other catch blocks
    finally {
        http.reset();
    }

    resultArray = new String[resultLength][resultLength * 8];
    // put result into own Stringarray

    if (_isConnected) {
        callbackObj.processData(resultArray, resultLength);
    }
}
}

Any help would be soo appreciated! :) Cheers, Musipoo

Musipoo
  • 11
  • 2
  • Is `ConnectionCallback` the object that has access to the UI? That's what I'd like to look at. – Sotirios Delimanolis Aug 28 '13 at 14:54
  • I think in general the recommendation is to avoid running blocking code in a TimerTask, or any long running code for that matter. Have the TimerTask trigger (start) a connection Thread rather than run the connection code. – Peter Strange Aug 28 '13 at 20:53
  • @Sotirios Delimanolis `ConnectionCallback` is the interface which provides the data to the UI. But it gets the correct data in the first run so the references should be fine right? – Musipoo Aug 29 '13 at 08:18
  • @Peter Thanks for the advice, I will try that approach. But where is the difference, since the thread is actually doing the same thing then? – Musipoo Aug 29 '13 at 08:22
  • AFAIK, the difference is that the TimerTask actually runs on the same Thread that manages the TimerTasks, so by having a long running process, especially ones that might fail, you are compromising future Timer events. – Peter Strange Sep 02 '13 at 08:33
  • @Peter, I tried it for a while and now it's finally working! Thank you so much!! But I still don't fully understand it.. I've always closed the http connection in my finally statement so there should be no long running process then? And furthermore, the screen was always painted every couple minutes (just with the old data) so the timer was actually working somehow.. – Musipoo Sep 02 '13 at 12:09
  • @Musipoo you seem to be using UI methods like Dialog.alert from the timer task. This will cause an exception and kill the timer task. – Adwiv Sep 04 '13 at 10:37
  • @adwiv, you're right. Meanwhile I changed it, instead of the alert I'm pushing a new screen there with invokeLater() and then start the timer again! – Musipoo Sep 05 '13 at 07:16

1 Answers1

1

In the first place I'd advise you not to extend Thread unless you need to override custom threading behavior (that is often not the case and it would be too scary a thing to do). Instead, the recommended approach is to implement a Runnable and pass it to the Thread constructor. In JavaSE they have introduced a new Executors framework that gets rid of instantiating threads the old way. With timers it's similar but here you implement a TimerTask which is pretty much a Runnable (inherits from it), and then you schedule it.

Another issue with your code is that it starts a thread from within a the constructor, which is a dangerous thing to do, because every new instance created will spawn a new thread (the one asociated with the Timer). This is considered an antipattern. Never do this, and if you do, please document it and make sure everyone using this class will know about it. (More info here). Also it is confusing that a class extending Thread launches a Timer in its constructor, and it doesn't even override run (what is the inheritance for?).

These are just tips to make your code clearer and a bit safer, but that won't fix your problem. I think the problem might be in that you are updating the result variable but you are not putting it into resultArray (or maybe you ommited that code?).

Mister Smith
  • 27,417
  • 21
  • 110
  • 193
  • @ Mister Smith - I'm putting it into `resultArray` but I just posted it as a comment here to make the code a bit shorter, that should not be the issue. But thanks for the tips to make it cleaner, I didn't see that approach before. Can I start that Runnable class from another screen as well? I would like to start with a Loading-Screen, start the thread meanwhile and then push the actual Main Screen with the data. I tried that so far but it seems the thread is not being started. – Musipoo Sep 02 '13 at 09:09
  • You don't "start" a `Runnable`, you start the `Thread` that has been composed with that `Runnable`. Same thing with `Timer` and `TimerTask`s, just another example of composition. Of course you can start as many threads as you wish from everywhere in code (and this is why so many things can go wrong). In general you want to keep it simple. – Mister Smith Sep 02 '13 at 11:33
  • Yeah you're right, and it's sometimes really hard to understand where the errors come from. Anyway it's finally working now with a TimerTask that starts the whole Thread instead of the http call only. But as you've recommended I will keep in mind to document that clearly. Thank you! – Musipoo Sep 02 '13 at 12:16