How to pass or assign a value obtained in a runOnUiThread
Asked Answered
P

4

5

In a subclass of WebView, I have this in an overridden method of getTitle():

      @Override
      public String getTitle() {
        Activity a = getVoTts().getActivity();
        a.runOnUiThread(new Runnable() {
            public void run() { 
                String tit = VoWebView.super.getTitle();
            }
        });


       String title = tit;  // this is what I WANT to do, it won't compile of course
       ...
       ...
      }

But the String tit is closed in an anonymous Runnable class and thus of course cannot be accessed down the method.

Is there any technique or "trick" that would allow me to pass a value obtained in an anonymous Runnable class to statements down the lines (in the same method) or assign it to a data member?

Plaided answered 1/1, 2013 at 21:1 Comment(0)
B
5

One way would be by declaring an instance field and using it across the whole class. For example:

private String someText;

// ...

@Override
public String getTitle()
{
    Activity a = getVoTts().getActivity();
    a.runOnUiThread(new Runnable()
    {
        public void run()
        {  
            someText = VoWebView.super.getTitle();
        }
    });
}

EDIT:

Regarding the reason of why you have to declare a local variable as final (or in other word, compile time constant):

Imagine the following is valid in Java:

@Override
public String getTitle()
{
    Foo f = new Foo();

    Button b = getButtonReference();
    b.setOnClickListener(new OnClickListener()
    {
        public void onClick(View v)
        {  
            Boo o = f.someMethod();
        }
    });

    f = null;
}

At f = null, the foo object will be eligible for garbage-collected. So if you click the button, it's too late for the VM to invoke someMethod() on the foo object, since it's garbage-collected!

Baelbeer answered 1/1, 2013 at 21:3 Comment(5)
I think java requires the field to be final if it's shared with anonymous classes.Todd
No. It only requires local variables to be final. It requires a value to be returned, though.Raisin
+1 to you too. And you are correct: It would yell "I need final" for a local variable but not for a data member for some strange reason.Plaided
@Plaided See the extra elaboration on that.Baelbeer
@Baelbeer Accepting, for the great accompanying explanation. Now, if I only got a trick that would work locally inside the overridden getTitle() and thus would be re-entrant. :-)Plaided
A
1

Why don't you declare a global variable:

 private String title;

  @Override
  public String getTitle() {
    Activity a = getVoTts().getActivity();
    a.runOnUiThread(new Runnable() {
        public void run() { 
            title = VoWebView.super.getTitle();
        }
    });
  }
Apiarist answered 1/1, 2013 at 21:5 Comment(1)
+1 for a great workaround that would actually work in my particular situation. But isn't this not re-entrant?Plaided
F
1

You can use FutureTask as follows:

FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
    @Override
    public String call() throws Exception {
        // Compute your string
    }
});

runOnUiThread(task);
String title = task.get();
Fassett answered 3/1, 2014 at 14:28 Comment(0)
A
0

Update

According to a comment, .runOnUiThread() runs its runnable asynchronously, which means the task may or may not have run by the time we get to the "statements down the lines". Then it is impossible to get the results to those statements in the rest of the method (and none of the solutions here will help you with that).

Autocorrelation answered 2/1, 2013 at 10:21 Comment(1)
No need to speculate, since "runOnUiThread" is executed asynchronously.Mole

© 2022 - 2024 — McMap. All rights reserved.