I have tried to solve this for days but now i try my luck here.
I use an lazy load to show my images in a custom adaper.
i want to fade in images as they ar download loaded.
This is working BUT the Thread stops while animation is ON
public void run()
{
if(bitmap!=null) {
myProgressBar.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.VISIBLE);
Animation animation = new AlphaAnimation(0.0f,1.0f);
animation.setDuration(800);
imageView.startAnimation(animation);
imageView.setImageBitmap(bitmap);
}else {
myProgressBar.setVisibility(View.VISIBLE);
imageView.setVisibility(View.INVISIBLE);
imageView.setImageResource();
}
what I want to do is to show next row even if the privius animaion not are finished.
Any ides?
This is so because the thread hasn't anything more to execute after the line
imageView.setImageBitmap(bitmap);
is reached.
Although you set a duration of 800 ms, Java doesn't wait on the startAnimation line until this 800 ms are over. If you want to stop your thread after the animation is completed I would recommend to use an AnimationListener to get notified when the animation ends.
Related
I am trying to develop an app that takes a 15 seconds of video, allows the user to apply different filters, shows the preview of the effect, then allows to save the processed video to sdcard. I use ffmpeg to split the video into JPEG frames, apply the desired filter using GPUImage to all the frames, then use ffmpeg to encode the frames back to a video. Everything works fine except the part where user selects the filter. When user selects a filter, the app is supposed to display the preview of the video with the filter applied. Though 450 frames get the filter applied fairly quick, displaying the images sequentially at 30 fps (to make the user feel the video is being played) is performing poorly. I tried different approaches but the maximum frame rate I could attain even on the fastest devices is 10 to 12 fps.
The AnimationDrawable technique doesn't work in this case because it requires the entire images to be buffered into memory which in this case is huge. App crashes.
The below code is the best performing one so far (10 to 12 fps).
package com.example.animseqvideo;
import ......
public class MainActivity extends Activity {
Handler handler;
Runnable runnable;
final int interval = 33; // 30.30 FPS
ImageView myImage;
int i=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImage = (ImageView) findViewById(R.id.imageView1);
handler = new Handler();
runnable = new Runnable(){
public void run() {
i++; if(i>450)i=1;
File imgFile = new File(Environment.getExternalStorageDirectory().getPath() + "/com.example.animseqvideo/image"+ String.format("%03d", i) +".jpg");
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
myImage.setImageBitmap(myBitmap);
}
//SOLUTION EDIT - MOVE THE BELOW LINE OF CODE AS THE FIRST LINE OF run() AND FPS=30 !!!
handler.postDelayed(runnable, interval);
}
};
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);
}
}
I understand that the process of getting an image from SDCard, decoding it, then displaying it onto the screen involves the performance of the SDCard reading, the CPUs performance and graphics performance of the device. But I am wondering if there is a way I could save a few milliseconds in each iteration. Any suggestion would be of great help at this point.
I also did a similar thing. I used a ValueAnimator. The images is an array of the image ids. eg: R.drawable.park1
ValueAnimator animation = ValueAnimator.ofInt(0,44);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(1000);
animation.setRepeatCount(200);
animation.addUpdateListener(new AnimatorUpdateListener() {
int i;
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("TAG", "::onAnimationUpdate: "+(++i)+" value = "+animation.getAnimatedValue());
mImageViewPreview.setImageResource(images[(Integer) animation.getAnimatedValue()]);
mImageViewPreview.invalidate();
if(mImageViewPreview.getVisibility()!=View.VISIBLE){
animation.cancel();
}
}
});
animation.start();
You are correct in saying that the performance of SDCard reading is slow. In fact look at how many things you want done - creating a new file from an external location, decoding it and creating a new bitmap. And all this done on the UI thread.
I don't know how big your images are but have you tried possibly preloading some of them, putting them in a list and then just picking them from that list and displaying them in your handler code?
I realize storing 450 images in memory is quite a lot but the task could probably be split up. Say you have preload 100 bitmaps and start displaying them, and then have an Async Task preloading the other 100 into the next list(or possibly the same list) at the same time.
My Bad ! Found the culprit. Being used to NSTimer on iOS, I overlooked the importance of the line of code :
handler.postDelayed(runnable, interval);
That code responsible for scheduling the next frame process was being executed AFTER the current frame getting read from the SDCard, decoded and displayed on to the imageview.
ie. If the entire process of displaying the current frame took 25 milliseconds, the next frame processing would be scheduled after 25+33 = 58ms after previous frame.
I moved that line of code to the first line of the run{} method of the runnable thread , and BINGO !! FPS raised to 24-30 FPS even on a $100 android device.
Anyways thanks to #Valentin, #Pedro Bernardo and #Shashika for pointing out some valid possible solutions.
I have a set of 10 images, and I want to create an animation where I cross fade between them. I've been looking into built-in Drawable to achieve such a thing, but no luck on that part.
There is the AnimationDrawable, that switch between pictures, but it doesn't animate the switch.
There is the TransitionDrawable, that cross fade between two pictures, but no more than two.
Hell.
I looked for some solution on Google, but no luck on that part. So I'm thinking about implementing my own drawable to achieve such a thing. Would any of you have any pointers ?
Thanks in advance.
Not sure if you found an answer to this, but I had the same problem and ended up building my own class based on TransitionDrawable.
Usage:
CyclicTransitionDrawable ctd = new CyclicTransitionDrawable(new Drawable[] {
drawable1,
drawable2,
drawable3,
...
});
imageView.setImageDrawable(ctd);
ctd.startTransition(1000, 3000) // 1 second transition, 3 second pause between transitions.
The code for the CyclicTransitionDrawable is available on Github.
Well. Long time has passed, and you probably fixed the issue, but you got setEnterFaceDuration() for AnimationDrawable. Example:
mBackgroundAnimation = new AnimationDrawable();
mBackgroundAnimation.addFrame(getResources().getDrawable(R.drawable.background1), 5000);
// ... rest of the frames
mBackgroundAnimation.addFrame(getResources().getDrawable(R.drawable.background6), 5000);
mBackgroundAnimation.setEnterFadeDuration(1000);
mBackgroundAnimation.setOneShot(false);
With this code you have an easy cycling through 1..N images, each one remains 5s (5000ms) with a fade-in animation. Now, what i do is setting the background of my root RelativeLayout
mLayoutRoot.setBackground(mBackgroundAnimation);
mLayoutRoot.post(new AnimationStarterThread());
And the AnimationStarterThread class
private class AnimationStarterThread implements Runnable {
public void run() {
if(mBackgroundAnimation != null)
mBackgroundAnimation.start();
}
}
Ok guys, this may sound dumb, but I have been banging my head against the keyboard for some time now trying to figure out why this will not refresh. the basics: I have a little sample app that i am testing to see if i can rotate an image around a point a X amount of degrees, and show it one degree at a time to make a smooth animation. So I have a great sample i found that works great with a slider bar, basically setting the images rotation to a point on the slider bar, great! but.... when i try and create a for loop with a random number and use my for variable updating the image along the way every degree... it does nothing... and all i get is the updated image at the end... but when i drag my finger on he slider bar the graphic is updated instant as me spinning it... I cant figure out what i am doing wrong here... here is the code with the slider... i don't have my piece that creates the random number and draws it but essentially i did it behind a button click
essentially if you look at this piece i did the same behind a button again but it doesnt do it "real time". i called view.invalidate() and view.postinvalidate() to try to force it but no go...
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
curRotate = (float)progress;
drawMatrix();
}
private void drawMatrix(){
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
matrix.postRotate(curRotate);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bmpWidth, bmpHeight, matrix, true);
myImageView.setImageBitmap(resizedBitmap);
}
I think what you did was something like:
for (int degrees = 0 ; degrees < maxRotation ; i++) {
// perform the rotation by matrix
myImageView.invalidate();
}
This wouldn't work because invalidate() only schedules a redraw in the main thread event queue. This means that the redraw will be performed only when the current code has all been executed (in this case, the for cycle).
For a simple rotation a Tween Animation would be better suited. For more advanced stuff (like game animations) you might need to create a custom view or use SurfaceView.
Sounds like you're blocking the UI thread with your code to rotate the image.
I don't have any code to show you right now (reply back and when I'm home tonight I can post something that should help), but yuo will probably get better results placing your rotate code in an AsyncTask, see the Painless Threading area of the dev site for more info.
I was having the same problem, i used:
runOnUiThread(new Runnable() {
public void run() {
myImageView.setImageBitmap(image);
imageView.invalidate();
}
});
I have created an animation drawable and image view in my main game thread which is configured from the activity that handles the game thread (starting it etc.). My code in this handling activity looks like this:
mDistractionsThread.animation.addFrame(getResources().getDrawable(R.drawable.one), 1000);
mDistractionsThread.animation.addFrame(getResources().getDrawable(R.drawable.two), 1000);
mDistractionsThread.animation.addFrame(getResources().getDrawable(R.drawable.three), 1000);
mDistractionsThread.animation.setOneShot(false);
mDistractionsThread.imageAnim =(ImageView) findViewById(R.id.img);
mDistractionsThread.imageAnim.setBackgroundDrawable(mDistractionsThread.animation);
mDistractionsThread.animation.start();
And as you can see the variable mDistractionsThread is a handle to the thread itself. This compiles fine but only displays the first frame (R.drawable.one) and does not animate at all. What is it I have missed?
I tried to set animation.start() from run() within mDistractionsThread but that just gave me an fatal exception because the View can only be altered from the class that alters its fields - which in this case is not the game thread.
How can I resolve this and get it animating through the frames, and for bonus points, moving across the x-axis?!
Many thanks
It matters where you start the animation. Try starting it in onFocusChanged() in the activity. It should help
I'm creating a gallery view where I'm loading images from the web. While the images are loading, I want to display an animation as a placeholder for each image. I figured this could be done using an AnimationDrawable, however, the animation won't start. The first frame of the animation loads as expected, and if I use the same in for example onWindowFoucsChanged in an activity, everything works fine.
Inside the getView method of my GalleryItemCursorAdapter (which extends SimpleCursorAdapter) I'have the following snippet:
AnimationDrawable frameAnimation = (AnimationDrawable) mContext.getResources().getDrawable(R.drawable.loading);
holder.picture.setImageDrawable(frameAnimation);
frameAnimation.setCallback(holder.picture);
frameAnimation.setVisible(true, true);
frameAnimation.start();
holder.picture is an ImageView. I get no errors, and (very) similar code seems to work fine other places, leading me to believe this may be related to similar to the onCreate issues for animations reported elsewhere. I've tried some variations of the above code, too.
My questions:
Is there an easier/better way to display a loading animation?
What can I do to make the above example work (if at all possible)?
create a new thread and start ..
new Thread(new Runnable() {
public void run(){
// some code that runs outside the ui thread.
frameAnimation.start();
}
}).start();