android movie实现gif (包含sdcard)加载

android movie实现gif (包含sdcard)加载

首先先说说使用movie加载gif的弊端:
1.需要关闭硬件加速,这就意味着对CPU的 消耗要明显变大,之前用的CPU全志T501(很低端,性能不行),CPU消耗可以占到25%,当然,对于现在 的主流 手机来说,小菜一碟
2.只能加载gif,不能加载其他类型的图片;

优点:
1.相比较于glide(glide加载gif很鸡肋),gif图运行流畅;

下面直接上代码:


/**
 * @author : wengliuhu
 * @version : 0.1
 * @since : 2020/7/20
 * Describe
 */
public class GifView extends View
{
    private  final int DEFAULT_MOVIE_VIEW_DURATION = 1000;
    final int buffersize = 16*1024;
    private int movieMovieResourceId;
    private String movieFilePath = "";
    private Movie movie;
    private long movieStart;
    private int currentAnimationTime;

    private float movieLeft;
    private float movieTop;
    private float movieScale;

    private int movieMeasuredMovieWidth;
    private int movieMeasuredMovieHeight;

    private volatile boolean isPaused;
    private Context context;

    private boolean isVisible = true;
    public GifView(Context context)
    {
        super(context);
        this.context = context;
    }

    public GifView(Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);
        this.context = context;
//        GifView(context, attrs, -1);
        init(context, attrs, -1);
    }

    public GifView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(context, attrs, defStyleAttr);
    }

    public int getMovieMovieResourceId()
    {
        return movieMovieResourceId;
    }

    public void setMovieMovieResourceId(int movieMovieResourceId)
    {
        this.movieMovieResourceId = movieMovieResourceId;
        movie = Movie.decodeStream(context.getResources().openRawResource(movieMovieResourceId));
        requestLayout();
    }

    public String getMovieFilePath()
    {
        return movieFilePath;
    }

	/**
	*从SD卡中加载gif
	*/
    public void setMovieFilePath(String movieFilePath)
    {
        File file = new File(movieFilePath);
        if (!file.exists()) return;
        this.movieFilePath = movieFilePath;
        InputStream inputStream = null;
        try
        {
            inputStream = new BufferedInputStream(new FileInputStream(file), buffersize);
            inputStream.mark(buffersize);
            movie = Movie.decodeStream(inputStream);
            requestLayout();
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (inputStream != null)
            {
                try
                {
                    inputStream.close();
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }

    }

    public boolean isPaused()
    {
        return isPaused;
    }

    public void setPaused(boolean paused)
    {
        isPaused = paused;
    }

    private void init(Context context, AttributeSet attributeSet, int defstyle){
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        TypedArray array = context.obtainStyledAttributes(attributeSet,
                R.styleable.GifView, defstyle, R.style.Widget_GifView);

        //-1 is default value
        movieMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
        isPaused = array.getBoolean(R.styleable.GifView_paused, false);

        array.recycle();

        if (movieMovieResourceId != -1) {
            movie = Movie.decodeStream(context.getResources().openRawResource(movieMovieResourceId));
        }
    }



    public void play() {
        if (this.isPaused) {
            this.isPaused = false;
            /**
             * Calculate new movie start time, so that it resumes from the same
             * frame.
             */
            movieStart = android.os.SystemClock.uptimeMillis() - currentAnimationTime;
            invalidate();
        }
    }

    public void pause() {
        if (!this.isPaused) {
            this.isPaused = true;
            invalidate();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (movie != null) {
            int movieWidth = movie.width();
            int movieHeight = movie.height();
            /*
             * Calculate horizontal scaling
             */
            float scaleH = 1f;
            int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);

            if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
                int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
                if (movieWidth > maximumWidth) {
                    scaleH = 1.0f * movieWidth / maximumWidth;
                }
            }
            /*
             * calculate vertical scaling
             */
            float scaleW = 1f;
            int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);

            if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
                int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
                if (movieHeight > maximumHeight) {
                    scaleW = 1.0f * movieHeight / maximumHeight;
                }
            }
            /*
             * calculate overall scale
             */
            movieScale = 1f / Math.max(scaleH, scaleW);
            movieMeasuredMovieWidth = (int) (movieWidth * movieScale);
            movieMeasuredMovieHeight = (int) (movieHeight * movieScale);
            setMeasuredDimension(movieMeasuredMovieWidth, movieMeasuredMovieHeight);
        } else {
            /*
             * No movie set, just set minimum available size.
             */
            setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);
        /*
         * Calculate movieLeft / movieTop for drawing in center
         */
        movieLeft = (getWidth() - movieMeasuredMovieWidth) / 2f;
        movieTop = (getHeight() - movieMeasuredMovieHeight) / 2f;
        isVisible = getVisibility() == View.VISIBLE;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        if (movie != null) {
            if (!isPaused) {
                updateAnimationTime();
                drawMovieFrame(canvas);
                invalidateView();
            } else {
                drawMovieFrame(canvas);
            }
        }
    }

    /**
     * Invalidates view only if it is isVisible.
     * <br></br>
     * [.postInvalidateOnAnimation] is used for Jelly Bean and higher.
     */
    private void invalidateView() {
        if (isVisible) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                postInvalidateOnAnimation();
            } else {
                invalidate();
            }
        }
    }

    /**
     * Calculate current animation time
     */
    private void updateAnimationTime() {
        long now = android.os.SystemClock.uptimeMillis();

        if (movieStart == 0L) {
            movieStart = now;
        }

        int duration = movie == null ? 0 :movie.duration();

        if (duration == 0) {
            duration = DEFAULT_MOVIE_VIEW_DURATION;
        }

        currentAnimationTime = (int) ((now - movieStart) % duration);
    }

    /**
     * Draw current GIF frame
     */
    private void drawMovieFrame(Canvas canvas) {
        if (movie  != null){
            movie.setTime(currentAnimationTime);
        }
        canvas.save();
        canvas.scale(movieScale, movieScale);
        if (movie != null){
            movie.draw(canvas, movieLeft / movieScale, movieTop / movieScale);
        }
        canvas.restore();
    }

    @Override
    public void onScreenStateChanged(int screenState)
    {
        super.onScreenStateChanged(screenState);
        isVisible = screenState == View.SCREEN_STATE_ON;
        invalidateView();
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility)
    {
        super.onVisibilityChanged(changedView, visibility);
        isVisible = visibility == View.VISIBLE;
        invalidateView();
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility)
    {
        super.onWindowVisibilityChanged(visibility);
        isVisible = visibility == View.VISIBLE;
        invalidateView();
    }
}

接下来styles.xml:

<style name="Widget.GifView" parent="@android:style/Widget"/> <

下面是attrs.xml:

<declare-styleable name="GifView">

    <attr name="gif" format="reference" />

    <attr name="paused" format="boolean" />

</declare-styleable>

使用中遇到的问题:
1.如何从sdcard中加载gif,这一部分资料比较好,movie本身的decodeFile()方法执行会报错,需要转换另一种方式,通过IO流来做

public void setMovieFilePath(String movieFilePath)
    {
        File file = new File(movieFilePath);
        if (!file.exists()) return;
        this.movieFilePath = movieFilePath;
        InputStream inputStream = null;
        try
        {
            inputStream = new BufferedInputStream(new FileInputStream(file), buffersize);
            inputStream.mark(buffersize);
            movie = Movie.decodeStream(inputStream);
            requestLayout();
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (inputStream != null)
            {
                try
                {
                    inputStream.close();
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值