return a value after Activity.runOnUiThread() method
Asked Answered
S

3

9

Is it possible to return a value after Activity.runOnUiThread() method.

runOnUiThread(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int var = SOMETHING;

        // how to return var value.         
    }
});

In this post i see that it's not possible to return a value after Runnable.run() method. But how to use (implement) another interface and return a value after execution.

Hope it's clear for all.

EDIT

May help someone else.

I useD @Zapl's solution, and passED a parameter inside the Callable class constructor, like this :

class MyCallable implements Callable<MyObject> {

        int param;

        public MyCallable (int param) {
            // TODO Auto-generated constructor stub
            this.param = param;
        }

        @Override
        public MyObject call() throws Exception {
            // TODO Auto-generated method stub
            return methodReturningMyObject(this.param);
        }


    }
Stereotype answered 28/1, 2014 at 12:55 Comment(0)
G
15

If you really want to do it you can use futures and Callable which is roughly a Runnable but with return value.

    final String param1 = "foobar";

    FutureTask<Integer> futureResult = new FutureTask<Integer>(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            int var = param1.hashCode();
            return var;
        }
    });


    runOnUiThread(futureResult);
    // this block until the result is calculated!
    int returnValue = futureResult.get();

This also works for exceptions thrown inside call, they will be re-thrown from get() and you can handle them in the calling thread via

    try {
        int returnValue = futureResult.get();
    } catch (ExecutionException wrappedException) {
        Throwable cause = wrappedException.getCause();
        Log.e("Error", "Call has thrown an exception", cause);
    }
Giacobo answered 28/1, 2014 at 13:3 Comment(8)
I needed to pass a parameter in the callable method. I have update the question. Thanks so muchStereotype
@mansoulx if you rename int position; to int param you should have a working solution. Otherwise just use a final local variable as parameter. Edit: added final var example to answer.Giacobo
int param is the variable i used to iterate over a for loop. I don't think a final declaration will fit well ... ?!Stereotype
I don't understand. But MyCallable declares that it has a field position that is nowhere used and you do this.param = param; although there is no field named param (e.g. private int param; - can be final since nothing is changing that after construction).Giacobo
@mansoulx I'm confused now :) Did you solve your problem using MyCallable or is that a question? final in a for loop would work like pastebin.com/5wGZyTzQ btwGiacobo
Yes it's ok now :). ok your declare new final index to take i value, ok thank you again.Stereotype
@Giacobo // this block until the result is calculated! how will it block? the function will wait for UI to complete then continue the code followed?Gush
@Fei yes, exactly.Giacobo
P
1

The problem there is that you need to handle final variables to be passed to the runOnUiThread() method, and that implies that you cannot modify them inside. However, there is a trick, you can declare a non-primitive data structure prior to the runOnUiThread(), for example a String[] in the case you want to return a String. Of course, you'll need to declare it as final

Once done, in the runOnUiThread() method simply assign the return value you want in yourarray[0], so after you'll be able to access it once you're out the method.

---- EDIT ----

Example:

private void my_method() {
  final String[] your_array = new String[1];

  ...

  runOnUiThread(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int var = SOMETHING;

        your_array[0] = "Hello!!!";

        // how to return var value.         
    }
  });

  System.out.println("I've got a message! It says... " + your_array[0]);
}
Practical answered 28/1, 2014 at 12:59 Comment(8)
thanks for replying. what do you mean by access it once you're out the method. : does it mean I can access it just after runOnUiThread instruction ?Stereotype
I've updated my answer with an example of what I mean, I hope that's what you've been looking for.Practical
That is not guaranteed to work since the thread writing to your_array[0] is not guaranteed to be done at that point. You have to wait. And it will in practice pretty much never work.Giacobo
Correct. This could be combined with a CountDownLatch(1) to synchronize both events (assignation and access). A good example is in the Android reference: developer.android.com/reference/java/util/concurrent/…Practical
That might still be unsafe unless you add some volatile or in case of arrays use e.g. AtomicIntegerArray. Not sure if CountDownLatch establishes a proper happens-before relation. My guess is no.Giacobo
From the reference I understand that using CountDownLatch(1) is intended exactly for this, however, I agree with the rest of your comment.Practical
Ok I think my guess is wrong and you don't need volatile on top " actions in a thread prior to calling countDown() happen-before actions following a successful return from a corresponding await() in another thread." from the docs.Giacobo
grazie molte. Un trucco tanto semplice quanto efficace. Grazie.Theatrics
C
1

you can use handler to send message back.

check following example Android: When should I use a Handler() and when should I use a Thread?

Cladophyll answered 28/1, 2014 at 13:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.