37

I have a thread that uses a handler to post a runnable instance. it works nicely but I'm curious as to how I would pass params in to be used in the Runnable instance? Maybe I'm just not understanding how this feature works.

To pre-empt a "why do you need this" question, I have a threaded animation that has to call back out to the UI thread to tell it what to actually draw.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Yevgeny Simkin
  • 27,946
  • 39
  • 137
  • 236

5 Answers5

88

Simply a class that implements Runnable with constructor that accepts the parameter can do,

public class MyRunnable implements Runnable {
  private Data data;
  public MyRunnable(Data _data) {
    this.data = _data;
  }

  @override
  public void run() {
    ...
  }
}

You can just create an instance of the Runnable class with parameterized constructor.

MyRunnable obj = new MyRunnable(data);
handler.post(obj);
Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242
  • 3
    I like this approach, but how do I communicate with this class from inside my timer thread (the Runnable is out in the main UI thread). Can I just make the member public and set it in my timer thread prior to passing the Runnable to the handler? Seems too good to be true :) – Yevgeny Simkin Feb 03 '12 at 03:37
  • Sorry to reply late, edited my answer. – Lalit Poptani Feb 03 '12 at 04:57
  • For some reason I thought that if obj is created some place other than the UI thread, then when it tries to manipulate a View (in the main thread) the app will crash. I'll give it a whirl, thanks very much. – Yevgeny Simkin Feb 03 '12 at 05:42
  • 1
    If you would like to manipulate or invalidate a view, you can use `runOnUiThread()` or can use Handler to ivalidate the view on the UI thread. – Lalit Poptani Feb 03 '12 at 05:49
  • `run()` should be marked with `@Override`. I edited the answer. – Oliver Hausler Jul 05 '16 at 03:34
  • 1
    There's Consumer now for single parameters. – Daniel Sharp Nov 18 '18 at 15:26
8

There are various ways to do it but the easiest is the following:

final int param1 = value1;
final int param2 = value2;
... new Runnable() {
    public void run() {
        // use param1 and param2 here
    }
}
Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • I guess I should have specified that I'd like to avoid using global params in my class in this way... :) Thanks, but I'm really trying to get a method for passing arguments in or using some other construct that takes them (if Runnable doesn't) – Yevgeny Simkin Feb 03 '12 at 03:33
  • You can store them as fields in the Runnable but that's about it. You could also use a Callable. – Romain Guy Feb 03 '12 at 07:07
  • That is going to run into a synchronization problem when the second post is called before the first post has been handled by the Runnable. – marcelnijman Aug 09 '14 at 08:25
6

If you need to communicate information into a Runnable, you can always have the Runnable object constructor take this information in, or could have other methods on the Runnable that allow it to gain this information, or (if the Runnable is an anonymous inner class) could declare the appropriate values final so that the Runnable can access them.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
1

Although you can use any of the above the answer, but if you question is really concerned about android then you can also use AsyncTask.

Yuvi
  • 1,344
  • 4
  • 24
  • 46
-1

I think a found a simpler approach:

public interface MyRunnable extends Runnable {
    public void run(int data);
}

public void someMethod(int n, String s, MyRunnable r) {
   ...
   r.run(n);
   ...
}

the call:

someMethod(5, "Hello", new MyRunnable() {

    @Override
    public void run(int data) {
        // TODO Auto-generated method stub

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

    }
});
ilomambo
  • 8,290
  • 12
  • 57
  • 106
  • Except that `MyRunnable` does not extend `Runnable` so you won't be able to use it where a `Runnable` is expected. – assylias May 20 '13 at 14:52
  • @assylias An interface can extend runnable if needed. – ilomambo May 20 '13 at 15:48
  • Yes but that is not the issue. Typically you call `new Thread(new MyRunnable() {...});`, but that will call the `run()` method, not the `run(int data);` method. Unless you have the `run` method call the `run(int data)` method, but how do you pass the parameters then? Try using your proposal with a real example and you will see the problems. – assylias May 20 '13 at 16:04
  • 1
    @assylias I am using my proposal, but with methods I wrote, so I can call `run(data)`. I guess you are correct about the OS methods, which will call `run()` only. – ilomambo May 20 '13 at 16:41
  • @ilomambo The accepted answer is the proper way to do this. Due to the nature of the asker's question (passing a Runnable with arguments to be executed in another thread), this answer does not work at all. – Lo-Tan Dec 10 '14 at 23:03