This is one I'm not sure how to go about.
Basically I have an ASyncTask class thats doing its business as usual in the background. I'd like to do something after its finished. Now before you jump ahead and say "just use onPostExecute()", theres a catch. The method I need run is in the activity and not the Task class.
The way I see it, I have 2 options.
A:
CustomTask task = new CustomTask();
task.execute(passedParams);
//when(task.execute is finished)
{
doX();
}
I hope I can do it this way as Its so simple and lets me check when the task is completed without having to constantly poll it for activity and getStatus() on the activity.
I don't think I'll get this lucky but If anyone has a way of doing it, that'd be great
B:
Pass the activity as a paramater to the ASyncTask. This is messy and I'm not happy about using it but asides from that and the object reference, I don't know if it will work
CustomTask task = new CustomTask();
task.execute(passedParams,MyActivity);
Then in the Tasks onPostExecute, I can just have it call the MyActivity.doX();
C:
A third way would be to make the asynctask a private class in the activity itself but i really would like to keep it separate. Resusability and what not –
Any thoughts on this?
To summarize, Need to doX() after task.execute is finished. Any ideas appreciated.
D:
Ok I know I'm on a roll here. I keep thinking up new solutions. A class method or static method that can be called from any where.
public class ProfileSettings extends Activity
{
public static void doX()
{
//Logic...
}
}
From AsyncTask
MyActivity.doX();
Option B should work and is sometimes a good option, but sometimes I use anonymous classes for this. When you call it from your activity:
CustomTask task = new CustomTask() {
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
MyActivity.this.doX();
}
}.execute();
Option A:
Android API has already provided built-in function for this purpose AsyncTask.get():
CustomTask task = new CustomTask();
task.execute(passedParams);
Result result = task.get(); // <- Block UI thread and waiting for AsyncTask finish.
this.doX(result);
As you can see, this is a bad practice as it blocks UI thread and may cause ANR exception, By doing this, you are actually sacrifice the benefit of AsyncTask, and make it running synchronously with UI thread.
Option B and C:
Both are correct way of doing things, by calling doX() method in onPostExecute() method,
AsyncTask, as its name stated, run a background thread asynchronously with UI thread, and once the background thread is finished, onPostExecute method is called on UI thread. There is no way to tell exactly when onPostExecute method is called (i.e. when doInBackground method is finished) at project build time, as it is determined at app run time, the only thing we know is onPostExecute method is guaranteed to be called on UI thread at some point in the future, In another word, when writing code at project build time, we never know exactly when the doInBackground is finished and code execution jump back to UI thread outside onPostExecute method (Unless you implement some waiting mechanism in code like Option A). So the purpose of onPostExecute method is for processing everything after doInBackground method is finish, this is also why the only argument of onPostExecute method is the result returned from doInBackground method.
The difference between Option B and C is whether to implement AsyncTask as inner class or separate class. This has been aksed and discussed many times in StackOverflow. Most people think it is good to separate them for resusability reason or etc. From my point of view, I don't agree with it. Java Programming Language has its reason provide inner class syntax to suit some special coding situations, when talking about code refactoring from a OOP perspective, think more from problem abstraction level, not simply strip inner class out from Activity class at code level. As you can see in your example, by isolating AsyncTask from Activity, you don't gain any real benefit but rather increase the code complexity (need pass activity context reference between classes) to solve problem.
I think you real question is whether or not we should isolate AsyncTask inner class implementation from Activity. For a better OOP code refactoring (reusability, testability and etc.), checkout my answer in this StackOverflow question to see how to isolate business layer from application UI layer properly.
I was able to implement this feature with an interface:
http://howcanisolve.com/38646/android-java-equivalent-of-ios-block-callbacks
public interface ICallbacks {
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}
Then in your routine code just put a new instance of Callbacks:
public static void getPassagesForFirebaseUser(FirebaseUser user,
Context context, ICallbacks events) {
//here code and call ICallbacks methods
if(result){ events.onResponse(response); }
if(error){ events.onError(err); }
}
ultimately you can call the method with :
getPassagesForFirebaseUser(user, context, new ICallbacks(){
#Override
public void onResponse(JSONObject response){
//Success !!!
}
#Override
public void onError(VolleyError response){
//Error !!!
}
});
Option B is generally safer. But even then, you need to be careful. You need to store the instance of your Activity (not just the class) in the ASyncTask. And if the Activity gets destroyed while the task is running (what if the user presses the Back button?), you need to inform the task of this so the task doesn't try to call a method on a dead Activity.
And if the Activity comes back to life (after a screen rotation, for example) then you need to reattach the new Activity to the running task.
These things are fiddly.
Related
I am not writing my whole code, I have the following simple structure:
public class CreateEventActivity extends ActionBarActivity{
int x;
void onCreate(){
new AsyncTask1().execute();//here I change the value of x
Log.i("000000",String.valueOf(x));
}
public AsyncTask1 extends AsyncTask<Void, Void ,Void>{
// process include changing the vlaue of x to 4
Log.i("111111",String.valueOf(x));
}
}
in the log: the log with the tag 000000 appears before the log with tag 111111 what's going on?
First I thought the problem was because I am chainging the value of x in onPostExecute so I did so in doInBackground and the problem still the same.
what's going on?
AsyncTask is asynchronous. Quoting the documentation:
This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The reason that you use an AsyncTask is to do work in a background thread (e.g., download some data), followed by some work on the main application thread (e.g., update the UI based upon that data).
is there anyway to avoid this?
Get rid of the AsyncTask, or learn how to use it properly. Among other things:
Do not modify the same data in multiple threads without appropriate synchronization logic
Do not try to fork a background thread, then block the main application thread (which appears to be what you want), as that eliminates the entire point of the background thread in the first place
If you have work that you want to do when doInBackground() ends, put that work in onPostExecute(), not in statements that follow your execute() or executeOnExecutor() call.
That's the nature of an Async task.
Async Tasks are mostly being used for long running operations; like webcalls, I/O operations and so on as they can take a while.
If you want to have a callback when the AsyncTask finishes you can override the OnPostExecute() method
I have a AsyncTask class that is separate from the MainActivity.
protected void onPostExecute(ArrayList<String> result) {
System.out.println("flag1");
MainActivity.myLst=new ArrayList<String>();
MainActivity.myLst=result;
}
then I have the following code in my MainActivity.
public void onCreate(Bundle savedInstanceState) {
new AsyncTask().execute();
System.out.println("flag2");
System.out.println(myLst.size());
}
The program outputs the flag2 first and myLst.size is 0. If I negative to other activity and then come back to the main activity and myList.size has the correct size. I thought It should output everything and do the work in AsyncTask before the MainActivity.
The AsyncTask doesn't "do the work before MainActivity", that would defeat the purpose of an AsyncTask.
What you want to do is write up an interface to pass the value back to your Activity. This answer has a good example of that.
You're creating an AsyncTask to do stuff asynchronously.
You're saying to another thread that it has work to do, but you're not waiting his result to do yours, that's why "flag2" is written before the other.
if you want to wait the result, you need to implement a callback in onPostExecute()
Asynchronous means that it may be out of order. An asynchronous task often launches another thread that does the work in parallel, or in the background, to the main thread. You absolutely cannot assume that the asynchronous task will be completed when execute() returns!
Like other have said and like I have said in the comments to your post, async means asynchronously, and in your case means it will probably finish the onCreate code before finishing the async task.
Either put the AsyncTask class inside your MainActivity (and call some method to print on PostExecute), or implement an Observing/Observer style in your activities to be able to notify your main activity that the async task is over.
You can just overwrite the onPostExecute() method inside the the code that calls the Asynctask.
For example,you have a AsyncTask called myAsyncTask. Then in your Activity do it like this:
new myAsyncTask() {
#Override
protected void onPostExecute( Result result ) {
super.onPostExecute( result );
// Do something with result here
}
}.execute(value1);
I had the same issue, I wanted to get the result inside a fragment....
Look at this topic
I have a MVC-based Java application which I am building, and there is a particular method within my controller (shown below) which behaves as follows:
The model is updated via the initialize method, as I would intend.
The update to the view is not occurring because the model.start() method never terminates (since it is an infinite while loop).
I want to have my view to update first, and then be able to start() my model. How do I alter my code to get the desired behavior?
I suppose one workaround would be replace the model.start() line with code that fires an event which my model is able to observe, but I have not tried that yet, because I want to understand the source of my problem.
Also, I have no idea if this is relevant, but my main application class defines a separate thread for my swing components via SwingUtilities.invokeLater(new Runnable()..., and my view is made up of swing components. There may be some issue related to multiple threads executing, and if so, that would explain why my initializedPerformed() method is not executing in a synchronous way.
Method in the controller which does not behave like I expect/want:
public void initializePerformed(Event e) {
model.initialize(e);
view.getPanel().setName(model.getName());
model.start();
}
model.start():
public void start() {
while (true) {
}
}
If you need model.start() at all, which I highly doubt you do, then start it in a separate thread like this:
new Thread() {
public void run() {
model.start();
}
}
If model is actually inheriting from Thread, then you shouldn't be overriding start() at all. You should override run(), which is called after Thread.start(), and after the new thread has actually been created. If you override start(), no new threads will be created.
From what I remember about swing, all operations must be done by the "main" app thread (I forgot the technical name of it).
The pattern is : create threads to process your data, and leave the main thread only for display. When there is an event that should be displayed, notify the view but let the main thread change it (typically use the semaphore pattern, but if you find it too complex, you can also have an infinite loop that looks what's new each 100 ms for example and calls wait() to check again: business threads will change variables accessible to the main thread.
Best Regards,
Zied Hamdi
http://1vu.fr
When I want to do something in background, if the action is very simple: Like do "something in background" and then update the UI, instead of using an AsyncTask I'm considering to use (just for faster coding):
new Thread(){
public void run(){
final ArrayList<myObjects> objects= myDatabase.queryObjects();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateUIWith(objects);
}
});
}
}
But I really don't know if using "final" objects that way can result in memory leaks or have other kind of troubles.
Is using this method OK?
final only says to the compiler that you won't reallocate the objects variable in your code. There is no link between final and memory leaks.
If you use an anonymous inner class (the new Runnable...) you have to make objects final.
I am not very familiar with Android but if your updateUIWith() method does interact with UI objects, it might be an issue as I would assume UI updates need to run in a specific UI thread. If you don't update UI objects in that method then you code should be fine.
The question is: Is it a good idea to open a new thread for every little action? AsyncTask provides the convenience of the threads being managed by someone else, but when you declare a thread like you did, you're responsible for dealing with situation such as limitations on the number of threads.
Good afternoon.
I am unfamiliar with the activity life cycle in android and have been reading up as best as possible but I cannot figure how to solve the following in a nice manner.
I have an activity with a GLSurfaceView to draw various things on the screen. In the renderering thread for this GLSurfaceView I perform all the rendering as well as the actual update logic (I will seperate this out eventually).
The trouble I am having is from one of the "screens" drawn within the renderer I wish to end the Activity and have it call the various lifecycle methods.
Normally I might do this with System.exit(0); however ending the activity in this way does not seem to call the OnStop(); OnDestroy(); methods.
This might just be me being silly and not seeing an easy way of doing this but is there a way to access the Activity and call activity.finish(); without having to pass the reference to it all the way down?
This is probably less of an android question and more a general java problem? Sorry I am a little rusty at both. Maybe if someone could explain roughly how they handle an issue like this in their app.
You do need to obey thread safety rules and not call activity.finish() directly from your render thread. The best way to handle this is to post a runnable back onto the event queue for the UI Thread. And let that Runnable call activity.finish().
You don't have to pass the activity down to the area where you plan on stopping the activity. Here is what I'd do. Pass the activity to the class you instantiate in onCreate(). Something like:
public void onCreate( ... ) {
MyRenderer renderer = new MyRenderer( glSurface, this );
}
Then inside MyRenderer I'd do something like:
public void someMethodInRenderer() {
if( stop ) {
stop();
}
}
public void stop() {
Handler handler = new Handler();
handler.post( new Runnable() {
public void run() {
activity.finish();
}
} );
}
Notice the Handler used to post back to the UI thread. That makes it safe to call activity.finish(). I couldn't find any specific information in the docs stating it's safe or not safe to call finish() from another thread so to be on the safe side post it back.
Things to keep in mind. If someMethodInRenderer() is deep within the bowels in your program then you don't have to have access directly to the activity instance. You just need a reference so something that eventually calls to the activity to finish. So maybe there is a reference to another part of the system you are passing down to that method where you can add the stop(). So stop() and someMethodInRenderer() could be in the same class, or in different classes. That's a choice you'll have to make. Eventually this is an architecture issue you have to decide.
If the renderer thread is inside the Activity, you can use ActivityClassName.this.finish();
To address an issue I ran into:
If you finish your activity (including from another thread) via activity.finish() it is important that the render thread's onDraw() method is not blocked (happened to me due to my implementation of double buffer rendering).
In that case, only the onPause() method in the activity class got called. The methods onStop() and onDestroy() weren't called even though the app finished with a short delay.
Hope this helps anybody facing the same problem.
Edit: The reason was, that in my activity.onPause() method I called glSurfaceView.onPause() while the render thread's onDraw() was blocked.