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();
}
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();
}
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;
}
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
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";
}
}