首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android异步任务框架动画

Android异步任务框架动画
EN

Stack Overflow用户
提问于 2016-03-03 16:21:19
回答 1查看 1.4K关注 0票数 0

首先,我尝试了很多在Android中制作流畅动画的方法,而我最好的选择可能就是使用AnimationDrawable.。一切都很完美,直到我走出了旧设备上的异常记忆。原因很明显是帧数,在我的例子中是75帧。这就是我如何使用Thread.sleep()、AsyncTask、和来动画帧的方法。为了避免动画滞后,我使用了Stack,在其中我预加载了前10帧,然后弹出使用过的帧,然后推送一个新的,直到没有更多的帧。一切都比我预期的要好,但唯一的问题是,在动画结束时,最后一帧消失了,我一整天都在敲击我的头,以理解为什么会发生这种情况,但显然没有成功。下面是我调用动画的活动和动画代码所在的文件中的代码。

SplashActivity.java

代码语言:javascript
复制
private void startAnimation() {
        gifImageView = (LogoAnimImageView) findViewById(R.id.gifImageView);
        gifImageView.setSplashActivityContext(this);
        gifImageView.setBackgroundResource(R.drawable.logo_frame_0);
        gifImageView.setAnimImageViewListener(new LogoAnimImageView.LogoAnimImageViewInterface() {
            @Override
            public void animationEnd() {
                mAnimationFinished = true;
                LoadNextActivity();

            }
        });
        gifImageView.startLogoAnimation();

    }

LogoAnimImageView.java

代码语言:javascript
复制
public class LogoAnimImageView extends ImageView {

    public interface LogoAnimImageViewInterface {
        void animationEnd();
    }

    final Handler mHandler = new Handler();

    private Stack<Drawable> mImageStack;

    private SplashActivity mSplashActivity;

    private LogoAnimImageViewInterface mListener;

    private int mFrameIndex;

    private int[] mResources = {R.drawable.logo_frame_0,R.drawable.logo_frame_1,R.drawable.logo_frame_2,R.drawable.logo_frame_3,
            R.drawable.logo_frame_4,R.drawable.logo_frame_5,R.drawable.logo_frame_6,
            R.drawable.logo_frame_7,R.drawable.logo_frame_8,R.drawable.logo_frame_9,R.drawable.logo_frame_10,
            R.drawable.logo_frame_11,R.drawable.logo_frame_12,R.drawable.logo_frame_13,R.drawable.logo_frame_14,
            R.drawable.logo_frame_15,R.drawable.logo_frame_16,R.drawable.logo_frame_17,R.drawable.logo_frame_18,
            R.drawable.logo_frame_19,R.drawable.logo_frame_20,R.drawable.logo_frame_21,R.drawable.logo_frame_22,
            R.drawable.logo_frame_23,R.drawable.logo_frame_24,R.drawable.logo_frame_25,R.drawable.logo_frame_26,
            R.drawable.logo_frame_27,R.drawable.logo_frame_28,R.drawable.logo_frame_29,R.drawable.logo_frame_30,
            R.drawable.logo_frame_31,R.drawable.logo_frame_32,R.drawable.logo_frame_33,R.drawable.logo_frame_34,
            R.drawable.logo_frame_35,R.drawable.logo_frame_36,R.drawable.logo_frame_37,R.drawable.logo_frame_38,
            R.drawable.logo_frame_39,R.drawable.logo_frame_40,R.drawable.logo_frame_41,R.drawable.logo_frame_42,
            R.drawable.logo_frame_43,R.drawable.logo_frame_44,R.drawable.logo_frame_45,R.drawable.logo_frame_46,
            R.drawable.logo_frame_47,R.drawable.logo_frame_48,R.drawable.logo_frame_49,R.drawable.logo_frame_50,
            R.drawable.logo_frame_51,R.drawable.logo_frame_52,R.drawable.logo_frame_53,R.drawable.logo_frame_54,
            R.drawable.logo_frame_55,R.drawable.logo_frame_56,R.drawable.logo_frame_57,R.drawable.logo_frame_58,
            R.drawable.logo_frame_59,R.drawable.logo_frame_60,R.drawable.logo_frame_61,R.drawable.logo_frame_62,
            R.drawable.logo_frame_63,R.drawable.logo_frame_64,R.drawable.logo_frame_65,R.drawable.logo_frame_66,
            R.drawable.logo_frame_67,R.drawable.logo_frame_68,R.drawable.logo_frame_69,R.drawable.logo_frame_70,
            R.drawable.logo_frame_71,R.drawable.logo_frame_72,R.drawable.logo_frame_73,R.drawable.logo_frame_74

    };

    public LogoAnimImageView(Context context) {
        super(context);
    }

    public LogoAnimImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LogoAnimImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void startLogoAnimation() {

        mFrameIndex = 10;
        mImageStack = new Stack<Drawable>();
        for (int i=1;i<=mFrameIndex;i++) {
            Drawable drawable = getDrawable(mResources[i]);
            mImageStack.push(drawable);
        }
        mFrameIndex++;
        mSplashActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                new LogoAnimOperation().execute((Object)null);
            }
        });



    }

    public void setSplashActivityContext(SplashActivity splashActivity) {
        this.mSplashActivity = splashActivity;
    }

    public void setAnimImageViewListener(LogoAnimImageViewInterface listener) {
        this.mListener = listener;
    }

    private Drawable getDrawable(int id) {
        Drawable drawable;
        if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
            drawable = mSplashActivity.getDrawable(id);
        } else {
            drawable = mSplashActivity.getResources().getDrawable(id);
        }
        return drawable;
    }

    private class LogoAnimOperation extends AsyncTask<Object,Void,String> {

        @Override
        protected String doInBackground(Object... params) {
            int number=1;
            while (mImageStack.size() > 1) {
                try {
                    Thread.sleep(40);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                final Drawable drawable = mImageStack.pop();
                mSplashActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            LogoAnimImageView.this.setBackground(drawable);
                        }
                        else {
                            LogoAnimImageView.this.setBackgroundDrawable(drawable);
                        }
                        if (mFrameIndex < mResources.length) {
                            Drawable newDrawable = getDrawable(mResources[mFrameIndex]);
                            mImageStack.push(newDrawable);
                            mFrameIndex++;
                        }

                    }
                });

            }

            return "";
        }

        @Override
        protected void onPostExecute(String s) {
            mSplashActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Drawable drawable = getDrawable(R.drawable.logo_frame_74);
                    if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        LogoAnimImageView.this.setBackground(drawable);
                    }
                    else {
                        LogoAnimImageView.this.setBackgroundDrawable(drawable);
                    }
                }
            });
            mListener.animationEnd();
            super.onPostExecute(s);
        }
    }

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-05 19:16:13

...but,唯一的问题是,在动画结束时,最后一帧消失了,我一整天都在敲我的头,以理解为什么会发生这种情况,而且显然没有成功。

问题可能在于你的AsyncTask's onPostExecute(String)

代码语言:javascript
复制
@Override
protected void onPostExecute(String s) {
    mSplashActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Drawable drawable = getDrawable(R.drawable.logo_frame_74);
            if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                LogoAnimImageView.this.setBackground(drawable);
            } else {
                LogoAnimImageView.this.setBackgroundDrawable(drawable);
            }
        }
    });
    mListener.animationEnd();
    super.onPostExecute(s);
}
  1. onPostExecute(String)将始终在UI线程上被调用。因此,mSplashActivity.runOnUiThread(....)是多余的。
  2. 通过使用runOnUiThread(Runnable),您将发送到UI线程的事件队列。所以,当轮到它时,运行程序就会被执行。但是,mSplashActivity.runOnUiThread(....)调用后的代码可能会在可运行之前执行。因此,在您的mListener.animationEnd()有机会显示R.drawable.logo_frame_74之前,可能会调用R.drawable.logo_frame_74

但是,这不应该发生在你的情况下。如果从UI线程(它是这样的)调用runOnUiThread(Runnable),则不会将Runnable提交到事件队列,而是立即执行。

我怀疑这里真正的问题是动画(R.drawable.logo_frame_74)的最后一帧和下一个活动的启动之间没有任何延迟。也许您可以注释掉对mListener.animationEnd()的调用,以检查动画是在最后一帧还是第二帧结束。

虽然这是一种有趣的方法,也是我以前从未见过的一种方法,但我不得不说,您处理的线程太多了。如果您试图在需要时加载Drawables,有一种更简单的方法:

代码语言:javascript
复制
public class LogoAnimImageView extends ImageView {

    ....
    ....

    // flag to indicate whether `mNextFrameDrawable` should continue loading the next frame
    private boolean mStopAnimating;

    // loads the next frame, and calls back to activity when done
    private Runnable mNextFrameRunnable = new Runnable() {
        @Override
        public void run() {
            if (!mStopAnimating) {
                if (isFinishedAnimating() && mListener != null) {
                    mListener.animationEnd();
                } else { // Load next frame
                    setViewBg(getNextFrameDrawable());
                    // Will load the next frame in 40 ms
                    postDelayed(this, 40L);
                }
            }
        }
    };    

    // This method can be set `public static` and placed in a separate `Utils` class
    private void setViewBg(Drawable d) {
        if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            setBackground(drawable);
        } else {
            setBackgroundDrawable(drawable);
        }
    }   

    private Boolean isFinishedAnimating() {
        return mFrameIndex >= mResources.length; 
    } 

    // returns the next frame's drawable and increments the `mFrameIndex` pointer
    private Drawable getNextFrameDrawable() {
        return getDrawable(mResources[mFrameIndex++]);
    }

    // start animating
    public void startLogoAnimation() {
        mFrameIndex = 0;
        mStopAnimating = false;
        post(mNextFrameRunnable);
    }

    // stop animating
    public void stopLogoAnimation() {
        mStopAnimating = true;
        removeCallbacks(mNextFrameRunnable);
    }

    ....
    ....
}

AsyncTask既不需要,也不适合处理这样的场景。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35777512

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档