Is there a way to pass parameters to a Runnable? [duplicate]
Asked Answered
G

5

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.

Giddens answered 3/2, 2012 at 3:25 Comment(0)
A
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);
Ablation answered 3/2, 2012 at 3:32 Comment(6)
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 :)Giddens
Sorry to reply late, edited my answer.Ablation
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.Giddens
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.Ablation
run() should be marked with @Override. I edited the answer.Affiance
There's Consumer now for single parameters.Huckleberry
R
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
    }
}
Rubin answered 3/2, 2012 at 3:27 Comment(3)
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)Giddens
You can store them as fields in the Runnable but that's about it. You could also use a Callable.Rubin
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.Amputate
D
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!

Dowson answered 3/2, 2012 at 3:27 Comment(5)
Will Callable be ok with being run from a thread that isn't the UI thread? The reason I'm doing this to begin with is that you can't just call out to the main thread in Android if you're going to alter any UI elements.Giddens
@Dr.Dredel- Yes, any thread should be able to run a Callable.Dowson
+1 for using an anonymous class extending Runnable and referencing final variables, as long as it's only used in one spotConsistent
-1 for saying Callable accepts parameters. A Callable returns a result, but the call method signature doesn't accept parameters.Estonian
@JohnSums You're right! Let me go fix that.Dowson
C
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.

Chew answered 3/2, 2012 at 4:10 Comment(1)
AsyncTask can manipulate Views in the UI thread (I realize this is only relevant in Android)?Giddens
T
-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

    }
});
Takakotakakura answered 20/5, 2013 at 13:44 Comment(5)
Except that MyRunnable does not extend Runnable so you won't be able to use it where a Runnable is expected.Moorland
@Moorland An interface can extend runnable if needed.Takakotakakura
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.Moorland
@Moorland 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.Takakotakakura
@Takakotakakura 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.Zamora

© 2022 - 2024 — McMap. All rights reserved.