I have implemented a way of getting the result from onPostExecute back to my main activity. I wanted to know if this is the right thing I did, is there any more chance of improving it, and if it's not the best way, what is the best way?
This is what I have done:
public class MainClass implements AsyncResponse {
private MyAsyncTask asyncTask;
public MainClass() {
asyncTask = new MyAsyncTask();
asyncTask.asyncResponse = this;
}
public void startTask( {
asyncTask.execute("string");
}
#Override
public void processDone(String res) {
// got response in MainClass from onPostExecute
}
private class MyAsyncTask extends AsyncTask<String, String, String> {
protected AsyncResponse asyncResponse = null;
#Override
protected String doInBackground(String... urls) {
return "some processed string";
}
#Override
protected void onPostExecute(String res) {
this.asyncResponse.processDone(res);
}
}
}
Here's the AsyncResponse interface:
public interface AsyncResponse {
void processDone(String res);
}
I want to know in terms of processing speed that on an average android mobile device, would this be a good approach and if not, how do I improve it to make it a good approach?
Thanks.
I always done this way and never had any issues. I would say it is the best way.
in one Line without any callback
String s= new MyAsyncTask().execute().get();
You added an unnecessary interface - and perhaps it makes your code less usable.
First, if you create the AsyncTask as a class within your Activity there is no need for the interface. You can simply do this:
#Override
protected void onPostExecute(String res) {
processDone(res);
}
The AsyncTask will execute onPostExecute on the UI thread and you can call the Activity method without the interface.
Second, if you create AsyncTask outside the Activity class (for example, in its own java file) then you can use this method, except it is not a good idea because it will hold a reference to the Activity on another thread - it's a memory leak risk.
To avoid that, your interface should be implemented in a separate class, like AsyncTaskResponse.java that is passed to the AsyncTask class.
Last, AsyncTask provides the response in the form of a String if that is sufficient. You should look at the docs on AsyncTask:
https://developer.android.com/reference/android/os/AsyncTask.html
You are wrapping the AsyncTask inside another POJO class; doing this doesn't hurt, but provides little benefit.
Consider that when the task is completed, you will want a callback notification somewhere. Your MainClass will get a callback in processDone(), but something will need to be listening to MainClass to get that notification.
Here is a pattern I always use with my AsyncTask subclasses:
public class GetDataRemoteTask extends AsyncTask<String, Void, Data> {
private static final String TAG = "GetDataRemoteTask ";
private WeakReference<GetDataResultListener> mListenerRef;
private Exception mExc;
#Override
protected Data doInBackground(String... params) {
Data result = null;
try {
result = mService.getData(params[0], params[1], params[2]);
} catch (Exception e) {
Log.e(TAG, "Error occurred getting data", e);
mExc = e;
}
return result;
}
#Override
protected void onPostExecute(Data result) {
if (mListenerRef != null) {
GetDataResultListener listener = mListenerRef.get();
if (listener != null) {
if (mExc == null) {
listener.dataReceived(result);
} else {
listener.dataException(mExc);
}
}
}
}
public void setGetDataResultListener(GetDataResultListener listener) {
if (listener == null) {
this.mListenerRef = null;
} else {
this.mListenerRef = new WeakReference<GetDataResultListener >(listener);
}
}
public static interface GetDataResultListener {
public void dataReceived(Data data);
public void dataException(Exception exc);
}
}
So to start off, here I have an interface, like you do, for connecting to the AsyncTask. But I don't wrap my AsyncTask with an implementation, I expect that I will have an Activity or a Fragment that will implement this interface. (That's why I use a WeakReference; if the Activity finishes, my AsyncTask won't keep holding on to the Activity. But that also means I can't use an anonymous class listener unless the client holds the reference for it.)
My client code will look like this:
GetDataRemoteTask task = new GetDataRemoteTask();
task.setListener(this);
task.execute(param1, param2, param3);
I also have a way to find out if there was an exception that occurred in the background task. Any background exceptions should always be reported to the client, which can decide how best to deal with the exception - for example pop up a dialog for the user, so they know the request failed.
I think that a big drawback of AsyncTask is that it doesn't have more structure around handling exceptions that occur in the background thread.
My task holds a reference to the exception, but I have also used Pair<Data, Exception> as a type parameter for return result so I don't need the exception property.
Using this pattern has helped me avoid some typical problems that occur when coding AsyncTask subclasses.
Related
I'm going round in circles trying different techniques but every time hitting a different snag.
Ideally I want my code to look something like;
public class MyActivity extends AppCompatActivity {
SomeMethod();
new SomeAsyncTask().execute();
SomeOtherMethod();
new SomeOtherAsyncTask().execute();
}
But I need each method to be executed in order (and to wait for the previous to complete). Let's imagine the first AsyncTask authenticates and stores an authentication token in a static somewhere- this is then needed for the calls which follow.
My AsyncTasks have to be Async as they are communicating with an API.
I know I could use the onPostExecute() methods of the AsyncTasks but I don't like the mess this creates (having to jump around the code).
I know I could also create an interface and pass a class in to my AsyncTask but this doesn't help a great deal either (code still jumps around).
I thought I had come up with the perfect solution, calling SomeAsyncTask.execute().get() to wait until the task completes before continuing with the next line of code BUT I've hit a few issues with that today too.
Are there any other techniques I might be able to use to achieve clean code with a mix of foreground and background thread activity?
EDIT At the moment I am considering whether I can make all of my method non-async but then call them from an async- more like;
public class MyActivity extends AppCompatActivity {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground( final Void ... params ) {
SomeMethod();
SomeMethod2();
SomeOtherMethod();
SomeOtherMethod2();
return null;
}
#Override
protected void onPostExecute( final Void result ) {
// any ui stuff
}
}.execute();
}
EDIT2 Current favoured solution is;
Define a "PostExecute" interface in my AsyncTask;
public class GetMerchantDataAsync extends AsyncTask<Void, Void, Void> {
private Context mContext;
private PostExecute mDelegate;
public interface PostExecute {
void Callback();
}
public GetMerchantDataAsync(Context context, PostExecute delegate) {
mContext = context;
mDelegate = delegate;
}
#Override
protected Void doInBackground(Void... params) {
}
#Override
protected void onPostExecute(Void v){
mDelegate.Callback();
}
}
Then define an instance of the interface and pass it on the constructor;
public class StartActivity extends Activity {
private final Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new GetMerchantDataAsync(context, getMerchantDataPostExecute).execute();
}
private GetMerchantDataAsync.PostExecute getMerchantDataPostExecute = new GetMerchantDataAsync.PostExecute() {
#Override
public void Callback() {
DoSomethingElse();
}
};
}
It's a little bit messy (not a single block of code) but it almost reads as a single block and hopefully with sensible/consistent naming will be easily readable.
There are many ways to skin this cat and a few nice async await libraries you can use, similar to Promise.
Or you can also simply do onPostExecute call backs inline if that fits your needs and call the next step onPostExecute, assuming life cycle is still valid.
However, if you want some nice clean code, you should consider Kotlin and Coroutines.
Example with Timeout, cancellation and error handling:
Notice the withTimeout and the withContext calls. Those allow you to await on the contents within before moving on. Also as an added bonus, the method here is a suspendable coroutine which means the caller can wait on it as well. You resume the caller with c.resume(returnValueType).
If you find this too complicated, then I would stick with your onPostExecute, but what most developers forget on AsyncTasks are.
AsyncTasks should be canceled if you exit the Activity typically
AsyncTasks can complete out of order if you are allowing threadpool
management
Object locks must be wrapped to ensure concurrent
modification of variables does not become a problem.
Callbacks should handle errors and not just the positive route
Timeouts have to be managed outside of the Async task adding much more bloat.
So you see, simply doing a myAsyncTask.execute{onPostExecute(value){//dostuff}}
may look like simple fast code, it is definitely prone to errors if you don't handle all the niche cases that can occur.
The Coroutines have provided nice wrappers around all of this in easy to read brackets.
private suspend fun updateConfigurationWithChanges() : Boolean = suspendCoroutine { c ->
A35Log.v(mClassTag, "updateConfigurationWithChanges")
setIsActionInProgress(true)
mSaveOrUpdateJob = launch(UI) {
try{
withTimeout(TIMEOUT_FOR_DB_INTERACTION_MS){
showProgressDialog(mClassTag, "Saving", false)
mSelectedConfiguration!!.setLastSavedDateStr(DateTimeHelper.getNowTimeStamp())
val updatedRecordCount = withContext(DefaultDispatcher){ SSDBHelper.updateConfiguration(mSelectedConfiguration!!) }
if(updatedRecordCount > 0){
showFancyToast("Successfully updated", true, FancyToast.SUCCESS)
c.resume(true)
}else{
showFancyToast("Error while updating, please try again or press back", true, FancyToast.SUCCESS)
c.resume(false)
}
}
}catch(ex: JobCancellationException){
showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
c.resume(false)
}catch (ex: TimeoutCancellationException) {
showFancyToast("Timed out updating, please try again or press back", true, FancyToast.ERROR, "Timed out updating database: ${ex.message}")
c.resume(false)
}catch(ex: Exception){
showFancyToast("Error updating database, please try again or press back", true, FancyToast.ERROR, "Error updating database: ${ex.message}")
c.resume(false)
}
}
}
Of course it is still good practice to cancel if the user leaves your screen if it doesn't hurt anything.
override fun onPause() {
super.onPause()
if(mSaveOrUpdateJob != null && mSaveOrUpdateJob!!.isActive) {
A35Log.v(mClassTag, "canceling saveOrUpdate job")
mSaveOrUpdateJob?.cancel()
}
}
But at the end of the day, do what's best for your situation, if managing the asyncTask and onPostExecute works for your needs and you have all your i's dotted and your t's crossed you should be fine going that route as well.
Also just for completeness if you are wondering how to call and await this above method it would look like this.
fun myButtonClick(){
launch(UI) {
if(mIsNewConfiguration){
//save first if new
if(withContext(DefaultDispatcher){ isNewOrUnchangedName() }) {
if (withContext(DefaultDispatcher) { saveNewConfigurationToDatabase() }) {
refreshCurrentNamesList()
launchConnectAndSendToDeviceFlow()
}
}
}else {
//update first if changes made
if(withContext(DefaultDispatcher){ isNewOrUnchangedName() }) {
if(DeviceAndConfigurationHelper.hasConfigurationModelChanged(mOriginalCopyConfiguration!!, mSelectedConfiguration!!)){
if(withContext(DefaultDispatcher) { updateConfigurationWithChanges() }){
refreshCurrentNamesList()
launchConnectAndSendToDeviceFlow()
}
}else{
launchConnectAndSendToDeviceFlow()
}
}
}
}
}
Happy Coding.
I can think of two approaches, depending on your constraints you can pick any of them, one using custom async tasks:
Create a custom AsyncTask which will be inherited by all your async tasks (or it can be done inline too):
public abstract class BaseAsyncTask<T, U, V> extends AsyncTask<T, U, V> {
public interface Callback<X> {
void onComplete(X param);
}
private Callback mainCallback;
public void execute(Callback<V> callback, T... params) {
mainCallback = callback;
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
#Override
protected void onPostExecute(V v) {
super.onPostExecute(v);
if (mainCallback != null) {
mainCallback.onComplete(v);
}
}
}
This can be used like this for your case:
public static class TestThinghy {
BaseAsyncTask<String, String, String> task = new BaseAsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... strings) {
return null;
}
};
void firstFunOnMainThread() {
//....do whatever...///
}
void runEverything() {
firstFunOnMainThread();
new BaseAsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... strings) {
return "testing thinghy";
}
}.execute(new Callback<String>() {
#Override
public void onComplete(String param) {
secondRunOnMainThread();
//you can start new async here, or better start it from a different methond
}
}, "the other string param");
}
void secondRunOnMainThread() {
///...whatever here
}
}
The other approach is using RxJava, it's a powerful approach that gives you a ton of ways to chain tasks like this and decide how to run them, for this approach I would let you to do some research.
I am sorry for my bad english skills. I'm new to programming/stackoverflow and try to create a little android quiz app. This app has to connect to a php server and login/getquestion...
The simplest example is the login. The user has to type in his data and then i have to connect.
To provide that the Gui doesnt freeze i have to use asynchronous tasks.
Here the activity's code:
public void login(final String username, final String password) {
final Activity a = this;
FutureTask t = new FutureTask(new Callable() {
public Object call() {
Connection.GetInstance(a).login(username,password);
afterLoginTry(username,password);
return null;
}
});
t.run();
}
This calls a method in another class, which calls another FutureTask which calls an AsyncTask. At the end there is always an public synchronized method such as afterlogintry(). This works but it's a bit slow and i think dirty code.
My main problem is that i don't know how to give results back through different layers of classes and especially to the activity without using hotfixes all the time.
Is there any good explanation or tutorial, which describes how to design such a construct?
Thx for help
The way you can pass AsyncTask results back to other classes, is by declaring callbacks for the task, that will then report the result to a listener. Here is how it works.
First, you must declare an interface in your AsyncTask which contains a method that will send out the result of the task. So in my example task below, my result is a String. The String gets passed to onPostExecute() when the task finishes its work. I then call my callback method on a registered listener, and pass that return value on to whoever is listening for it. You register a listener by passing in an instance of your callbacks from whichever class is creating the task.
public class MyTask extends AsyncTask<String, Void, String> {
MyTaskCallback listener;
public MyTask(MyTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... params) {
String input = params[0];
//do work
input += "did some work on this String";
return input;
}
//When the thread finishes its work, this gets
//called on the main UI thread
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface MyTaskCallback {
void onResultReceived(String result);
}
}
So next we need to register a listener for these callbacks, so when the result comes in from the task, it will get reported directly to our class. So let's say we have a simple Activity. The way we register the callbacks is to use the implements keyword on our class declaration, and then to actually implement the callback method in the class itself. We then create our task, and we pass in this which is our Activity that implements the callbacks. A simple example Activity that does this looks like this:
public class TaskActivity extends AppCompatActivity implements MyTask.MyTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
//we pass in "this" because our Activity itself
//implements the callbacks below.
MyTask myTask = new MyTask(this);
myTask.execute();
}
//Here we implement our callback method, so the task
//can send its results straight through here
public void onResultReceived(String theResult) {
Log.d("TASK RESULT", "Here is our result String: "+theResult);
}
}
Now, our task has our Activity connected to it, through the callbacks we passed into it. So now when our task gets a result, we can send it directly to our listener, which is our Activity, and the result will come right through to our implemented onResultReceived method.
Callbacks are a great way to pass information around between classes while also keeping everything very separated. Hope this helps!
I have been trying to change textView after I'm done networking in an another thread with AsyncTask. I've tried countless solutions, but none have worked so far.
The only way I was able to achieve my goal was to use .get(), but it stops the UI thread for a while, and that's something I don't want.
I've also tried using the AsyncTask as an outer class, and using a wrapper class in the middle.
So my question here is, what is the easiest way to get hold of a variable used in doInBackground() and onPostExecute(), without freezing the main thread?
Here is a way to do it. You can give a callback in parameter of your async task, do whatever you want and them get the value back from the async task.
Callback interface :
public interface AsyncTaskCompleteListener<T> {
public void onTaskComplete(T result, int number);
}
AsyncTask :
public class LoadURL extends AsyncTask<String, Process, String> {
private AsyncTaskCompleteListener<String> callback;
public LoadURL(AsyncTaskCompleteListener<String> cb) {
this.callback = cb;
}
protected void onPreExecute() {}
protected String doInBackground(String... arg0) {
// do something
return content;
}
protected void onPostExecute(String content) {
if (callback != null)
callback.onTaskComplete(content,number);
}
}
Activity :
public class LoginActivity extends Activity implements AsyncTaskCompleteListener<String> {
#Override
protected void onCreate(Bundle savedInstanceState) {
LoadURL loadUrl = new LoadURL(LoginActivity.this);
loadUrl.execute(...);
}
#Override
public void onTaskComplete(String result, int number) {...}
}
in onTaskComplete, you can easily modify your TextView
Just update the UI in the following code inside the AsyncTask:
#Override
protected void onPostExecute(Int result) {
textView.setText(result.toString());
}
Check this link if you need extra help.
You should return the variable from doInBackground(). Framework will make sure you will get the returned value in onPostExecute().
onPostExecute runs on the UI thread so you should be able to refresh any UI element here.
Let's say you're designing the threading architecture for a an app -> the primary purpose is that your app will have a lot of tasks that need something done on the background thread, and sometimes a result task on UI thread, or something not (though more times, the result needs to be run on UI thread). For simplicity, let's say the tasks will be stuff like: download a file and display a pop-up, log a user in and go to a different page, process an image and store the result in a database (popular tasks that a lot of apps do)
I've researched a lot about the nuances, but would really like a deep-dive explanation/knowledge on what kind of architecture is better, and what are the considerations.
here are the three models in consideration:
AsyncTask model: each operation (like downloading a file and displaying a pop-up) is an AsyncTask, or some derivative of a parent class that abstracts out the common functionalities.
Thread/handler model: i always create a new Handler(Looper.getMainLooper()); and each time i need to do a task, i use a thread factory to spin off the task, with the handler on UI thread (or whatever custom handler).
Service/Thread model: i use a general Service class that is in charge of operations based on some operation code. there's a bunch of ServiceTask derivative objects that do certain things, but the Service class communicates with each ServiceTask when tasks are started/done.
I'm slightly leaning towards going the whole service/threading model, just because i've read some really awkward nuances with AsyncTask/Threads:
AsyncTask has a private static handler, and if the classloader calls it at the wrong time (such as including a library that uses it before your application does) then all of your onPostExecute will happen at the wrong time since your handler was not the main handler
it's easy to forget to check a bunch of things in the onPostExecute such as if there was a config change, or your activity was destroyed, or application was backgrounded/paused when the onPostExecute is called (leading to crashes)
AsyncTask changed its serial/parallel execution behavior on different APIs
If you went with the Thread/Handler model, on older devices, thread priority is actually incredibly low. i've heard something like there was a priority scale of 1-15 such that your threads automatically get a low priority and if the system was low on resources, your threads would stop running (whereas since services are running independently of your activity the thread priority there is higher?)
What is the best way to design a robust threading architecture that doesn't easily lead to crashes/unexpected behavior while also maintaining good performance ??
Please also let me know in the comments if this question is too vague and if you need actual code (i'm afraid to post code because it would super overbloat the question length more than it already is).
I don't think you will find a one-size fits all approach here.
Downloading a file? Use DownloadManager
Logging a user in and go to next screen? Probably an AsyncTask would be best.
Process an image and store it? A Service might be a good choice here since you don't want the action to be attached to any particular Activity.
Handlers are more tricky, if they are attached to a Looper running on a background thread you need to call quit() on the Looper when you are done with it. Handlers are good when you need to delay an action, postDelayed() is great for that. They are also good when you need to communicate back to the UI thread from a background thread.
But yes you are correct that each one has pitfalls as you mentioned. Android is a complex beast and it seems they could have a done a better job preventing developers from shooting themselves in the foot, especially in regards to AsyncTask being called after an Activity is destroyed!
I was using Java's old school approach by creating a class (I called it ThreadRunner) derived from Java's Thread. A constructor looked like:
public ThreadRunner (Object [] params, AbstractCallback callBack) {...}
AbstractCallback was a class that was implemnting a single 'onCall' method and was mostly used to notify a calling party about an event such as "execution of a task is completed".
I've used it to get content from Internet and run other time consuming operations. It didn't cause any problems and worked as expected.
However, I've heard many times that AsyncTask is an Android-ish way of doing things like that. I don't know why and do not have any intention to change, since I'm preaching "don't fix it if it's not broken" approach.
I've seen also comments that you'll need to write less code with AsyncTask, but in my approach with traditional Java's Threat the amount of coding was small as well, so I queses it's just a matter of your personal preferences and experience.
In regard of your 3-rd approach - I think you should use it when write a service that runs all the time, listens on requests and never stops. When you just need to execute a single task asynchronously Java Threads or AsyncTask should be used.
I think AsyncTask is a good tool for listed purposes. But it needs to wrap AsyncTask for an easy using. My variant of such wrapping (with a progress indicator) is a following:
Main class AsyncActivity for extending it in application activities:
public abstract class AsyncActivity extends Activity{
// Поле нужно обязательно объявить как статическое!
private static AsyncConnect asyncConnect = null;
protected void runBackgroundTask(String progressInscription, RequestTask task){
asyncConnect = new AsyncConnect(this, responseListener, progressInscription, task);
asyncConnect.execute();
}
protected abstract void onBackgroundTaskEnd(boolean result);
#Override
protected void onResume(){
super.onResume();
// Перерегистрируем текущий контекст этой формы
// для корректной работы слушателя ответа с сервера
responseListener.registerCurrentContext( this );
if (asyncConnect != null){
asyncConnect.onResume(this);
}
}
#Override
protected void onPause(){
super.onPause();
if (asyncConnect != null){
asyncConnect.onPause();
}
}
/**
* Чтобы диалоги не вызывались из устаревшего контекста
* и по этой причине не исчезали при повороте экрана,
* слушателя ответа с сервера необходимо сделать статическим полем класса,
* в котором должен быть зарегистрирован текущий контекст
*/
private static final OnServerResponseListener responseListener = new OnServerResponseListener(){
private AsyncActivity context = null;
#Override
public void registerCurrentContext(AsyncActivity context){this.context = context; }
#Override
public void onResponse(boolean result){
// Если никакой контекст не был зарегистрирован, ничего не делаем
if (context == null) return;
// Освождаем статическое поле для сборщика мусора (но делать это не обязательно!)
asyncConnect = null;
// Вызываем колбэк о завершении фоновой задачи
context.onBackgroundTaskEnd(result);
}
};
}
Additional class and a pair of interfaces:
public class AsyncConnect {
private final Activity context;
private final RequestTask task;
private final String progressInscription;
private final OnServerResponseListener responseListener;
private boolean isDone = false;
private ProgressDialog progressDialog;
public AsyncConnect(Activity context, OnServerResponseListener responseListener,
String progressInscription, RequestTask task){
this.context = context;
this.task = task;
this.progressInscription = progressInscription;
this.responseListener = responseListener;
progressDialog = null;
isDone = false;
}
public void execute(){
if (isDone) return;
new ConnectTask().execute();
}
public void onPause(){
if (isDone) return;
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
}
public void onResume(Activity context){
if (isDone) return;
progressDialog = ProgressDialog.show( context, null, (CharSequence)progressInscription,
true, false);
}
private class ConnectTask extends AsyncTask<Object, Void, Boolean> {
#Override
protected void onPreExecute( ) {
super.onPreExecute();
progressDialog = ProgressDialog.show( context, null,
(CharSequence)progressInscription, true, false);
}
#Override
protected Boolean doInBackground(Object... messages) {
return task.call();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
// Делаем невозможным повторное использование этого объекта
isDone = true;
responseListener.onResponse(result);
}
}
}
public interface OnServerResponseListener {
public void registerCurrentContext(AsyncActivity context);
public void onResponse(boolean result);
}
public interface RequestTask {
public boolean call();
}
For using AsyncActivity we only need to call runBackgroundTask and implement onBackgroundTaskEnd in the target activity. It's possible to create different kinds of AsyncTask wrappings based on this idea.
You may also check out Needle; it's an open-source, simple but powerful multithreading library for Android. With it you can say things like:
Needle.onMainThread().execute(new Runnable() {
#Override
public void run() {
// e.g. change one of the views
}
});
or
Needle.onBackgroundThread().execute(new UiRelatedTask<Integer>() {
#Override
protected Integer doWork() {
int result = 1+2;
return result;
}
#Override
protected void thenDoUiRelatedWork(Integer result) {
mSomeTextView.setText("result: " + result);
}
});
very simple API
fixed thread pool size
customizable thread pool size
supports UI interaction ("do work and then use result on UI thread")
android 1.5+
behaves the same on all platform versions
Check it out on GitHub: https://github.com/ZsoltSafrany/needle
say I want to perform an Http request from the server, this process takes time.
now because of this, the http request needs to be run on a different thread (AsyncTask, Runnable, etc.)
but sometimes I just need the response when I ask for it, in order to update the UI
using Thread.sleep in a loop to wait for the response is not good performance wise
example: I want the user's name, I ask the server for it, and I have to wait for it
now the activity calls the UserManager that calls the serverHandler that performs the operation and returns the result back
maybe an event system is in order, but I'm not sure how to do this in my scenerio
and quite frankly I am really confused on this issue
please help someone?
This can most definitely be done w/ AsyncTask... Handle the network request in doInBackground() and once doInBackground() is finished, onPostExecute() is triggered on the UI thread and that's where you can execute any code that will update UI elements.
If you need something a bit more generic and re-usable, you would probably want to implement a callback... I'll refer to the UI thread as the client and the AsyncTask as the server.
Create a new interface and create some method stubs.
public interface MyEventListener {
public void onEventCompleted();
public void onEventFailed();
}
Have your client pass instance of MyEventListener to the server. A typical way of doing this is to have your client implement the interface (MyEventListener) and pass itself to the server.
public class MyActivity implement MyEventListener {
public void startEvent() {
new MyAsyncTask(this).execute();
}
#Override
public void onEventCompleted() {
// TODO
}
#Override
public void onEventFailed() {
// TODO
}
}
On the onPostExecute of the server, check if the callback is null and call the appropriate method.
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private MyEventListener callback;
public MyAsyncTask(MyEventListener cb) {
callback = cb;
}
[...]
#Override
protected void onPostExecute(Void aVoid) {
if(callback != null) {
callback.onEventCompleted();
}
}
}
You can read more about callbacks here: http://www.javaworld.com/javaworld/javatips/jw-javatip10.html