I'm trying to return value from my asynctask in DoInBackground, but calling get() method freezes my UI. How can I re-write my code to a callback method? :
public class GetUrlDataTask extends AsyncTask<String, Integer, String> {
String response;
HttpUtils util;
@Override
protected String doInBackground(String... params) {
try {
util = new HttpUtils(params[0]);
response = util.getContent();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
In my activity I get result as response = new GetUrlDataTask().execute("site").get;
[UPDATE] Now i suggest to use annotations. With annotations you can inject views, make function as asyncronous process on the compilation step with just a few letters. Check out butterknife library on github.
ButterKnife
You can create interface, pass it to AsyncTask (in constructor), and then call method in onPostExecute
For example:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted();
}
Your Activity:
public YourActivity implements OnTaskCompleted{
//your Activity
}
And your AsyncTask:
public YourTask extends AsyncTask<Object,Object,Object>{ //change Object to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted listener){
this.listener=listener;
}
//required methods
protected void onPostExecute(Object o){
//your stuff
listener.onTaskCompleted();
}
}
You shouldn't use .get() if the Async task is going to take any decent amount of time (which it usually is).
Instead, you can either use a message/handler/service/etc, or you can simply use the onPostExecute(Result) method.
EDIT: New Code. Based on your description, it seems like you need to use an interface.
If you need to have Asynctask in another class, then an interface is probably your best option.
TestTask.java (your separate Asynctask):
import android.os.AsyncTask;
// Remember to change object type <> to what you need
public class TestTask extends AsyncTask<Object,Object,Object> {
public interface OnTaskCompleted{
void onTaskCompleted();
}
private OnTaskCompleted listener;
public TestTask(OnTaskCompleted listener){
this.listener = listener;
}
protected void onPostExecute(Object o){
// Call the interface method
if (listener != null)
listener.onTaskCompleted();
}
@Override
protected Object doInBackground(Object... params) {
// The sleep() is just to simulate activity and delay
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
MainActivity.java (or any other activity):
public class MainActivity extends Activity {
private boolean status = false;
private OnTaskCompleted listener = new OnTaskCompleted() {
public void onTaskCompleted() {
status = true;
Toast.makeText(MainActivity.this, "Status: " + status, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(MainActivity.this, "Status: " + status, Toast.LENGTH_SHORT).show();
new TestTask(listener).execute("Testing");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
I'm not a big fan of having AsycTask tasks in separate classes, especially if you need to use the response. It makes interacting with the response and local variables overly difficult considering how easy it is when implemented as an inner class.
I'm guessing you put it in its own class so you can reuse it. I would consider keeping the AsycTask as an inner class and calling outside reusable objects/methods in doInBackground(). This will keep the code DRY and allow your activity to do what it needs with the response.
public class MyActivity extends Activity {
TextView textview;
//...
private class GetUrlTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... params) {
return new GetHttpResponse().get(params[0]);
}
protected void onPostExecute(String response) {
//Do UI updates...
textview.setText(response);
}
}
}
public class GetHttpResponse {
public String get(String url) {
try {
util = new HttpUtils(url);
response = util.getContent();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
}
You could do something like this:
public class MyActivity extends Activity
{
public void someMethod()
{
// Here you could put up a ProgressDialog
GetUrlDataTask myTask = new GetUrlDataTask();
myTask.execute();
}
public class GetUrlDataTask extends AsyncTask<String, Integer, String>
{
@Override
protected String doInBackground(String... params)
{
String response = null;
HttpUtils util;
try
{
util = new HttpUtils(params[0]);
response = util.getContent();
}
catch (Exception e)
{
e.printStackTrace();
response = e.getMessage();
}
return response;
}
@Override
protected void onPostExecute(String result)
{
// Here you can dismiss the ProgressDialog and display the result
}
}
}