0

I am using a Thread to perform an HttpURLConnection and get data from my database. The code below represents what I would like to accomplish but I get an error on the line

str_Data = "John Doe";

Error: Variable 'str_Data' is accessed from within inner class

public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.MainActivity);

    String str_Name = "";

    str_Name = setDataToText(str_Url);

}

 private String setDataToText(String urlStr) {
    final String url = urlStr;
    String str_Data = "";

    new Thread() {
        public void run() {
            //A code to retrieve data is executed
            //Data is Converted and added to the string str_Data;
            str_Data = "John Doe";
        }
    }
    return str_Data;
}

I would like to set the value of str_Data inside the run() operation on my new Thread() to the data that was recovered from my Database.

EDIT: THIS IS HOW I SOLVED THE PROBLEM, Let me know if it is not good practice when using this method, thanks for the help:

String str_Data = "";

public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.MainActivity);

setDataToText(str_Url);
txtName.setText(str_Data);
}

private void setDataToText(String urlStr) {
    new Thread(new Runnable() {
    @Override
        public void run() {
        // TODO Auto-generated method stub
        //A code to retrieve data is executed
        //Data is Converted and added to the string str_Data;
        str_Data = "John Doe";
        }
    }).start();
}
barracuda
  • 968
  • 3
  • 10
  • 26
  • There is no benefit of calculating the return value of a method in an own thread. You have to wait nonetheless for that result. What exactly are you trying to achieve? By the way, simply creating and instantiating an anonymous class (extending thread) does not start it. – Seelenvirtuose Jun 22 '15 at 05:56
  • Using a thread implies using a callback when the job is done. – SqueezyMo Jun 22 '15 at 05:58
  • You should use interface for proper implementation – Biraj Zalavadia Jun 22 '15 at 05:58
  • I am new to Java and Android. Can you elaborate on what is proper implementation? – barracuda Jun 22 '15 at 06:06

4 Answers4

3

The correct way of doing this is using Callable and Future interfaces.

public static void main(String[] args) throws ExecutionException, InterruptedException {
   ExecutorService executorService = Executors.newSingleThreadExecutor();
   CallableClass callableClass = new CallableClass();
   Future<String> future = executorService.submit(callableClass);

   String name = future.get();
   System.out.println(name);
}

public class CallableClass implements Callable<String> {

    @Override
    public String call() throws Exception {
       return "John Doe";
    }
}
Eranda
  • 1,439
  • 1
  • 17
  • 30
2

Use interface to make it work properly.

private interface DataListener{
        void onDataReady(String data);
    }

    private String str_Name = "";

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.MainActivity);

        setDataToText(str_Url, new DataListener() {
            @Override
            public void onDataReady(String data) {
                str_Name = data;
                System.out.println(str_Name);
            }
        });

    }


    private void setDataToText(final String urlStr,final DataListener dataListener) {


        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                //A code to retrieve data is executed
                //Data is Converted and added to the string str_Data;
                String str_Data = "John Doe";
                dataListener.onDataReady(str_Data);
            }
        }).start();


    }
Yuchen
  • 33
  • 4
Biraj Zalavadia
  • 28,348
  • 10
  • 61
  • 77
  • Hmmm ... OP says, he wants to _return_ the computed value in his method, and this computation should be done in an own thread (which is more difficult than that). Additionally, you are assigning the result of the method call to athe variable `str_Name`, but the method is `void`! – Seelenvirtuose Jun 22 '15 at 06:21
  • 1
    you can not return values from Thread. So interface is the way to get value back from the worker threads.If you don't know the thread that does't mean it is wrong and start down voting. If you know how to return value from thread then post the answer rather down vote. – Biraj Zalavadia Jun 22 '15 at 06:32
  • I downvoted your answer because it even doesn't compile and it is not a good approach (so maybe it is you who doesn't know much about threads). Using threads and callbacks is not as easy as you describe it here - for the scenario that OP is describing. – Seelenvirtuose Jun 22 '15 at 06:36
  • 1
    Then you post best approach my dear. – Biraj Zalavadia Jun 22 '15 at 06:39
  • oh FINALLY some sense in an answer on this page! thank you Biraj Zalavadia , and what's your problem guys? RETURN VALUE FROM THREAD??? are you srys? – Yazan Jun 22 '15 at 07:34
  • @Yazan I hope by now you read the question. It was specifically requesting a return value from a thread. It's actually quite possible using a callback, Handler, or AsyncTask. This version is the callback. – Abandoned Cart Jun 19 '19 at 22:37
1

You can do something like this.

String str_Data = "";

public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.MainActivity);

    String str_Name = "";

    str_Name = setDataToText(str_Url);

}

    private String setDataToText(String urlStr) {




        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                 //A code to retrieve data is executed
                //Data is Converted and added to the string str_Data;
                str_Data = "John Doe";
            }
        }).start();

        return str_Data;
    }
Shoeb Siddique
  • 2,805
  • 1
  • 22
  • 42
  • Setting a final variable is not allowed. Additionally, what do you think the method will return? A bad answer .. – Seelenvirtuose Jun 22 '15 at 05:55
  • As that final variable are unused. Please see my edits. – Shoeb Siddique Jun 22 '15 at 05:57
  • This method really helped me, it wasn't the exact answer but I worked it in. I got my code running: 1) setDataToText to return Void 2) added the "new Runnable() { @Override" statements. 3) defined the str_Data = ""; variable outside both functions. 4) Removed the variable str_ret altogether. – barracuda Jun 22 '15 at 07:03
  • what will happen if `run()` have more complex (time consuming) work? ... just asking :) – Yazan Jun 22 '15 at 07:36
  • You are on wrong path friend. you may stuck later on. – Biraj Zalavadia Jun 22 '15 at 11:29
  • 1
    The issue here is that there is no guarantee that `return str_Data` executes after `str_Data = "John Doe"`. That's why this is incorrect. – Eranda Jun 23 '15 at 01:06
0

You can't change the value of a local variable inside that thread. If you want to access variable in that thread, they need to be declared final, which implies that you cannot change their values.

Basically there is no sense in returning a value from a thread in your case, because you can't know when that value will be ready.

There are various of options to use the value you got from your database: you can use listeners, eventbus (use with caution), you can declare str_Data as a field in that class (but watch out what happens on screen rotation). So if you need to show that value in your layout, you can display a progress bar when you start the thread, and hide it + set the value you got in the layout when the thread finishes its work

Roi Divon
  • 1,147
  • 1
  • 11
  • 16
  • I don't want to access any variable inside the thread. I want to return a value that is generated inside the Thread. I want str_Data to be returned when setDataToText() is called. – barracuda Jun 22 '15 at 05:58