Android execute when multiple tasks are done - java

I'm working on an app that downloads information from my server after an NFC card has been detected.
When a card is detected, I start
- an Asynctask to download some data from my server
- an animation of a popup appearing on the screen
After both the asynctask and the animation are done, I want to start a method that displays the downloaded data in the popup.
What is the correct way to trigger this new method? It can only start when both conditions are met.

In the async task you use to download data add the onPostExecute method to remove the animation popup and show the downloaded data as well like this :
protected void onPostExecute(Long result) {
//put code to disable animation popup
//code for displaying downloaded data popup
}
For more info check out http://developer.android.com/reference/android/os/AsyncTask.html

you Animation object has the method setAnimationLister. It takes as parameter a Class Object that implements the interface Animation.AnimationListener . This interface requires three methods to be implemented:
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
The onAnimationEnd is triggered when the animation ends. If I have not misunderstood you, this is what you need
EDIT:
you could have two booleans value, boolean animationFinished = false, downloadFinished = false; When onPostExecute is called put downloadFinished to true and call yourMethod.
When onAnimationEnd is triggered animationFinished = true and call yourMethod. yourMethod should start like:
if (!animationFinished || !downloadFinished)
return;

Related

Is there a way to exactly detect when an activity is destroyed in android?

I am making an android app in java in which I need to trigger some database requests whenever an activity is completely destroyed which would probably happen if the user presses the back button or leaves the app itself... But the onDestroy() function in my app is randomly getting triggered even when the user is still on the activity... I guess the probable reason for this is configuration changes but I am not able to figure out a proper solution for this.
Is there a way we could exactly detect when an activity is left by a user avoiding any in-page configuration changes??
The onDestroy() that I am using is this:
#Override
protected void onDestroy() {
/// do smthng
super.onDestroy();
}
Any help would be appreciated!!
Solved:
Thank you for the answer guys... For me onStop() worked out perfectly and it is working in every case whether it might be pressing the back button or exiting the activity or the app itself!!
If you want to check if the user ended the activity, meaning pressed back, do this:
#override
public void onBackPressed(){
//do something before we finish the activity
super.onBackPressed();
}
If you want to check when user, goes to next activity, then resturns to the same activity:
#override
public void onResume(){
//do something when return back to this activity
super.onResume();
}
#override
public void onPause(){
//do something before going to another activity
super.onPause();
}
onDestroy is called when the activity is destroyed or finished and not guaranteed to be called always, don't depend on it
We can check on whether our application is foreground or background based on the activity entering and exiting the foreground by implementing ActivityLifecycleCallbacks.
Good reference : https://medium.com/#iamsadesh/android-how-to-detect-when-app-goes-background-foreground-fd5a4d331f8a
Quoting from the above article,
#Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
and,
#Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
by which we can make sure that our app is in foreground or not. Here you always have the control of what activity is in foreground based on which you can check and execute the logic.

How reliable is onAnimationEndListener?

I made an mediaplayer app with animations when the users plays the next song, the album art fades out and the album art for the next song fades in.
I first start the fade out animation and if this animation ends i send a broadcast to start the second song.
I would like to know if onAnimationEnd is reliable and will always called because if not then my app basically wouldn't work anymore for playing next/prev song.
private void nextSong(){
mAlbumArtLarge.startAnimation(fadeOutAnimation);
mAlbumIvBottom.startAnimation(fadeOutAnimation);
mAlbumArt.startAnimation(fadeOutAnimation);
tvSongTitle.startAnimation(fadeOutAnimation);
tvArtistName.startAnimation(fadeOutAnimation);
tvSongListSize.startAnimation(fadeOutAnimation);
fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (Main.getInstance().mServiceIsBound) {
Main.getInstance().mediaPlayerService.startActionNextSong(getApplication(), songList, songIndex);
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
From my experience it wasn't called in case you run an animation during the start onCreate()of activity in view.post{ startAnimation() } and by going to background during beginning of animation it didn't called the listener. Eventually the problem for me was usage of post(Runnable) on queue to execute on main thread, as it was called in onCreate(). I had resolved it by using onWindowFocusChanged() + post{}. Will update my answer after sometime of using it in production. For now tested it on different devices/APIs no problem occurred.
To think of : you can add some (safety workaround) Handler with timer (like 5 sec if animation doesn't ends you do next step there after 5s)

Call a method when fragment is visible to user

I need execute a method when the fragment is visible (to the user).
Example:
I have 2 buttons (button 1 and button 2) ,
2 fragments(fragment 1 and fragment 2)
and the method loadImages() inside the class fragment 2.
when I press "button2" I want to replace fragment 1 by fragment 2
and then after the fragment 2 is visible (to the user) call loadImages().
I tried to use onResume() in the fragment class but it calls the method before the fragment is visible and it makes some delay to the transition.
I tried setUserVisibleHint() too and did not work.
A good example is the Instagram app. when you click on profile it loads the profile activity first and then import all the images.
I hope someone can help me. I will appreciate your help so much. Thank you.
Use the ViewTreeObserver callbacks:
#Override
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
final View view = v;
// Add a callback to be invoked when the view is drawn
view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
#Override
public void onDraw() {
// Immediately detach the listener so it only is called once
view.getViewTreeObserver().removeOnDrawListener(this);
// You're visible! Do your stuff.
loadImages();
}
});
}
I'm a little confused by what you are trying to do. It sounds like the images are loading too fast for you... so does that mean that you have the images ready to display? And that is a bad thing?
My guess (and this is just a guess) is that Instagram does not have the profile pictures in memory, so they have to make an API call to retrieve them, which is why they show up on a delay. If the same is the case for you, consider starting an AsyncTask in the onResume method of the fragment. Do whatever loading you need to do for the images in the background, and then make the images appear in the onPostExecute callback on the main thread. Make sure you only start the task if the images are not already loaded.
However, if you already have the images loaded in memory, and you just want a delay before they appear to the user, then you can do a postDelayed method on Handler. Something like this:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadImages();
}
}, 1000);
Edit
As kcoppock points out, the handler code is pretty bad. I meant it to be a quick example, but it is so wrong I should not have included it in the first place. A more complete answer would be:
private Handler handler;
public void onResume(){
super.onResume();
if(handler == null){
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
loadImages();
}
}, 1000);
}
}
public void onDestroyView(){
super.onDestroyView();
handler.removeCallbacksAndMessages(null);
handler = null;
}
Use the onActivityCreated() callBck

Android animation only shows the last ArrayList element

I have 5 TextView fields that are meant to display a String and change the text every 10 seconds.
In order to make the change I have an AsyncTask that grabs the next 5 messages (doInBackground) and passes them to onPostExecute to be displayed in the UI.
When I display the messages without an animation, everything works perfectly fine and the messages rotate every 10 seconds via a new AsyncTask every time.
Now, when I attempt to use a simple fade-in/out animation on the TextViews, I can see all of them fading out and then back in with a placeholder string however the actual text messages I want to display are only displayed in the last TextView.
The AsyncTask is an inner-class of my MainActivity.java.
I have implemented an AnimationListener in MainActivity.java and due to that the objects below in onPostExecute ((TextView) mNextTextView & (String) mNextMessageToDisplay) are also declared as global variables in the main class.
Here's AsyncTask's onPostExecute:
protected void onPostExecute(List<String> mFiveMessagesToDisplay) {
super.onPostExecute(mFiveMessagesToDisplay);
for (int mTextViewCounter = 0; mTextViewCounter < 5; mTextViewCounter++) {
// Prepare the next TextView and message to use
mNextTextViewToUse = mTextViewArrayList.get(mTextViewCounter);
mNextMessageToDisplay = mFiveMessagesToDisplay.get(mTextViewCounter);
// Post and animate the message changes in the TextView
mNextTextViewToUse.startAnimation(mFadeOutAnimation);
}
}
And my AnimationListener:
private AnimationListener mFadeOutAnimListener = new AnimationListener() {
public void onAnimationStart(Animation animation) {}
public void onAnimationRepeat(Animation animation) {}
public void onAnimationEnd(Animation animation) {
mNextTextViewToUse.setVisibility(View.INVISIBLE);
mNextTextViewToUse.setText(mNextMessageToDisplay);
mNextTextViewToUse.setVisibility(View.VISIBLE);
mNextTextViewToUse.startAnimation(mFadeInAnimation);
}
}
As you can see, my setText() method is applied on the mNextTextViewToUse object with the contents of mNextMessageToDisplay, which are as mentioned before both global variables in the main class.
Both ArrayLists, the one containing the messages and the other containing the correct, I have iterated over both and printed the contents - everything is in its place.
Reminding again that if I use setText() with the same TextView and String objects under onPostExecute, everything works perfectly fine just without the animation.
Many thanks in advance!
Your issue is that the loops finishes by the time the animation ends, that's why you see only the last message.
Lets say that mNextTextViewToUse points to TextView1. You start a fade out animation for this TextView. By the time the animation ends, mNextTextViewToUse points to a different textView object (because the loop continue to run while the fade out animation is playing) so when onAnimationEnd is being called (by the fade out animation of TextView1) mNextTextView points to TextView5, and basically you are setting the text to this text view only.
There are several ways to solve this / implement what you need, personally I would probably create my own TextView class (extending TextView of course) and I'll add a public method called setTextAnimated (String newText). It will look something like:
public void setTextAnimated (String newText) {
mNextText = newText;
startAnimation(mFadeOutAnim);
}
where your onAnimationEnd callback will simple call setText(mNextText) and then will start fade-in animation.
Using this you will avoid another issue - that if you use the same animation object on different views - they will share the same timeline and interpolator. The result is that if View1 start a fade out animation that should take 200ms, and View 5 starts the same animation after 140ms, View5 will immediately "jump" to the same alpha value that View1 is.
I found the solution!
I ended up completely removing the FOR loop logic and using recursion which raises a Boolean flag once it has used all 5 available TextViews.
The method that gets the next TextView and String message and execute the animated setText():
public void updateTextView(List<String> mMessages) {
mNextTextViewToUse = mTextViewArrayList.get(mCurrentMessageIndex);
mNextMessageToDisplay = mMessages.get(mCurrentMessageIndex);
mNextTextViewToUse.startAnimation(mFadeOutAnimation);
if (mCurrentMessageIndex == 4) {
mStopMessageDisplayRepeat = true;
} else {
mCurrentMessageIndex++;
}
}
The Runnable that calls the method above, while the recursion stop Boolean is false:
public Runnable mUpdateTextViewRunnable = new Runnable() {
final static int POSTDELAY_INTERVAL = 600;
#Override
public void run() {
updateTextView(mFiveMessages);
if (! mStopMessageDisplayRepeat) {
mMessageDisplayRepeatHandler.postDelayed(mUpdateTextViewRunnable, POSTDELAY_INTERVAL);
}
}
};
Execute the Runnable:
public void startTextViewRunnableRepeat() {
mUpdateTextViewRunnable.run();
}
This is how my AsyncTask's onPostExecute() looks like:
#Override
protected void onPostExecute(List<String> mFiveMessagesToDisplay) {
super.onPostExecute(mFiveMessagesToDisplay);
mFiveMessages = mFiveMessagesToDisplay;
startTextViewRunnableRepeat();
}

Showing a progressdialog in android while a large method is executed

I have a long running method that is called during onCreate, this method populates textviews so interacts with the UI, and updates maybe 70 labels (about 3-20 seconds depending on device).
I want to display a progressdialog as this method executes.
Ideally I want to fire my method on the UI thread once the Activity has been displayed and the progress is displayed, this I cannot do, the Activity won't paint until the method has finished.
I hoped to find an event which was fired after the activity was displayed, and I found the one below, but it still leaves the screen black until the method has finished.
#Override
public void onPostCreate(Bundle savedInstanceState)
I am normally a WP7 developer, and in .NET you add an event handler for onLoadComplete which is fired after the ui is displayed, but before the user has a chance to interact withthe UI, how do I do this in Android JAVA?
Thanks
Put a ProgressBar in the View.
Then in the onCreate() or onResume() method do this:
new Thread() {
public void run() {
yourLargeMethod();
}
}.start();
Now you can do this inside your method to update the progressBar
public void yourLargeMethod() {
// doSomething
...
runOnUiThread(new Runnable() {
public void run() {
// update the progress from the thread
progressBar.setProgress(x); // x is your progress, 0 <= x <= progressBar.getMax()
}
});
}

Categories

Resources