0

I have this ToggleButton that is enabled when a certain condition (Website content) is true.

getSystemOnState(..) connects to a webserver and this causes an exception because of strict mode. What is wrong about the way I am using the Handler class?

public class ReceiverToggleButton extends ToggleButton {
 private Runnable mTicker;
 private Handler mHandler;
 private boolean mTickerStopped = false;
 private String rxhost = null;
 private Context context = null;

 public ReceiverToggleButton(Context context) {
    super(context);
    this.context = context;
    updateOnOffState(context);
 }

 private void updateOnOffState(final Context cxt) {
    Runnable r = new Runnable() {
        public void run() {
            rxhost = cxt.getResources().getString(R.string.host_receiver);
            mHandler = new Handler();
            mTicker = new Runnable() {
                public void run() {
                    if (mTickerStopped) {
                        return;
                    }

                    boolean isSystemOn = getSystemOnState(rxhost); // connects to webserver
                    setChecked(isSystemOn);
                    invalidate();
                    long now = SystemClock.uptimeMillis();
                    long next = now + 1000 * 10; // check every 10s
                    mHandler.postAtTime(this, next);
                }

            };
            mHandler.post(mTicker);
        }
    };
    new Thread(r).start();
 }
}
PhilW
  • 741
  • 6
  • 23

1 Answers1

1

Strict mode is complaining because you are still trying to do that network operation on the UI thread. Or this class is getting called into by a BroadcastReceiver (which are short lived). Handlers's are also ment to pass messages and you aren't really using them correctly in this example. Or at least you can see how all the Threads, runnables, and posting makes everything hard to read.

What you need here is AsyncTask.

Here is the Google example From http://developer.android.com/reference/android/os/AsyncTask.html

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

new DownloadFilesTask().execute(url1, url2, url3);

In your case, you will want the first parameter to be your host string, your do in background will perform your checks and your network call, and the onPostExecute (which runs on the UI thread) to update your views.

Frank Sposaro
  • 8,511
  • 4
  • 43
  • 64
  • Thank you! Now I am just wondering how I would use Handlers correctly - I used this [tutorial](http://www.vogella.com/articles/AndroidPerformance/article.html#concurrency_asynchtask), I fail to see what I am doing differently. – PhilW Jul 21 '12 at 16:23
  • Yeah. I suppose that way works, but it's not very clean. In my experience handlers are nice when you have 2 classes (typically on different Threads) that need to talk to each other. For example, a MusicService trying to send updates back out to an Activity. (The other way around can just use an IntentService) So I guess I've only had great success with one way communication of small messages (usually ids) that I switch on and perform some action. – Frank Sposaro Jul 21 '12 at 16:29
  • That's only slightly different from my use case (not the one posted, but same application). I have a textview that shows the current song played on a remote system (XBMC queried via HTTP). So every N seconds I want to query XBMC and show the song's name. My current approach is now AsyncTasks, scheduled using java.util.TimerTasks - I'll see if that works. – PhilW Jul 21 '12 at 16:37
  • Ahh I see. Well like I mentioned AsyncTasks are useful because you can perform your query on a background thread. Then pass that string to your onPostExecute and then update your UI. So your params should look something like AsyncTask Which basically maps to – Frank Sposaro Jul 21 '12 at 16:42
  • I just tried it using timer tasks - it does not work: I tried running Looper.prepare() once (to be able to make changes to the UI), but then the task aborts (not even a stacktrace) when calling back onPostExecute(). I guess I'll have to implement this using Threads, Tasks etc are good, but for repetitive uses not really helpful. – PhilW Jul 21 '12 at 16:55
  • Ahhh. You needs to call execute() on your AsyncTask from the UI thread, this can't be done from a runnable. – Frank Sposaro Jul 21 '12 at 17:06
  • I do, but it does not seem to work, see my [current code here](http://pastebin.com/uAisShiZ) - So, what I have is an expensive (IO) method that needs to pass its result to the UI every N seconds, what would you suggest? – PhilW Jul 21 '12 at 17:12
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14221/discussion-between-frank-sposaro-and-philw) – Frank Sposaro Jul 21 '12 at 17:15