24

I have the following :

Runnable done = new Runnable()
    {
        public void run()
        {
            System.out.println("Hello");
        }
    };

And then in my Android activity I'll call something like :

runOnUIThread(done);

Which I then call. However, I want that "Hello" not to be hardcoded, so I can pass it in. Otherwise I'll have to have one of these declarations for every String I want to print.

(This is actually an android question, but slimmed it down to basic Java so its easier to answer)

Thanks

Jimmy
  • 16,123
  • 39
  • 133
  • 213

2 Answers2

49

In Java (and I believe it is the same in Android too), you can use a anonymous inner class, like suggested by Bart van Heukelom. This solution has the advantage that have to write less code, and you could access fields and methods ouf the outer class.

But it has 2 drawbacks:

  • the variable "hello" has to be final,

  • the anonymous class has a internal reference to the outer class instance - this means the outer class being retained when it would otherwise be eligible for garbage collection. @See: Effective Java [Joshua Bloch], Item 22: Favor static member classes over nonstatic

And in my humble opinion, it is bad practice to parametrize a class instance in this way.

So I believe, as long as you do not need to access methods and fields of the outer class, it is better to write an specific class for this task and make it a static member class.

class Demo {
...

  private static class MyRunnable implements Runnable {
     private final String message;

     MyRunnable(final String message) {
       this.message = message;
     }

     public void run() {
       System.out.println(message);
     }
  }

  public void startThread() {
    MyRunnable myRunnable = new MyRunnable("Hello");

    runOnUIThread(myRunnable); 
  }
...
}
Yahel
  • 8,522
  • 2
  • 24
  • 32
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • 1
    is there a multithreaded solution where the `message` doesn't have to be final ? – Someone Somewhere Apr 23 '15 at 20:39
  • The `final` statement in this example is not necessary. - But when you use the Runable in mutlipe thread at once, you have to deal with concurrency problems! – Ralph Apr 24 '15 at 07:40
22
final String hello = whereverItsComingFrom;
Runnable done = new Runnable()
    {
        public void run()
        {
            System.out.println(hello);
        }
    };
Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • Not the best way, because, if you have something like so: public void receivedEvent(Event e) { queueEvent(new Runnable() { public void run() { System.out.println(e.message) } }); } You'll have a error. – Gustavo Maciel Dec 22 '11 at 02:05
  • 3
    @gtoknu then just make parameter e final – Bart van Heukelom Dec 22 '11 at 08:38
  • It'll make any difference to have the parameter as final? Explain further, please! I've thought about overriding methods that doesnt have a final parameter, i should call another method that receives a final and do what the first method would do? – Gustavo Maciel Dec 22 '11 at 15:56
  • @Gtoknu Unless I'm wrong, you can change a parameters finality when overriding or implementing, because it's not part of the method contract, just of the variable inside the method body. Even if you can't, you could just do `final Event ee = e`; – Bart van Heukelom Dec 24 '11 at 17:24
  • 1
    Hmm, glad to know. I think that my C++ experience bothers me. Because there, if you send a pointer of a function parameter to something like a runnable to run in another thread, the pointed data will likely be destroyed , and you'll get a runtime error of accessing invalid memory. – Gustavo Maciel Dec 24 '11 at 18:27
  • 'final'lity is not part of the public API in java. 'final' keyword in the arg list means it is not mutable inside the method; without 'final' the value may be changed during the method execution but that does not make it an inout parameter. http://stackoverflow.com/questions/5380177/final-arguments-in-interface-methods-whats-the-point – andersoj Sep 10 '12 at 01:24