15

假设我有大型动画 gif 的 URL,并且我想制作一个类似 youtube 的活动,以流式方式显示动画。我如何

  1. 图像中的流?
  2. 让它与实际动画一起显示?

我知道ImageView不是答案,因为它只显示第一帧。

一个好处是可以访问它的缓冲状态,这样我也可以同步流式声音——这是YTMND查看器应用程序的一部分。虽然我可以创建一个将公共 gif 文件转码为更好格式的服务,但我希望该应用程序能够在没有额外依赖项的情况下运行。

4

4 回答 4

12

解决方案的总体思路是使用定期View绘制请求的应用Movie程序来绘制自身。Canvas

第一步是构建Movie实例。有一个工厂调用decodeStream可以在给定的情况下制作电影,InputStream但仅使用来自 a 的流是不够的UrlConnection。如果你尝试这个,IOException当电影加载器尝试调用reset流时,你会得到一个。不幸的是,黑客是使用BufferedInputStream带有手动设置的分隔符mark来告诉它保存足够的数据而reset不会失败。幸运的是,它URLConnection可以告诉我们需要多少数据。我说这个 hack 很不幸,因为它实际上需要将整个图像缓冲在内存中(这对于桌面应用程序来说没有问题,但在内存受限的移动设备上却是一个严重的问题)。

这是Movie设置代码的片段:

URL url = new URL(gifSource);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bis.mark(conn.getContentLength());
Movie movie = Movie.decodeStream(bis);
bis.close();

接下来,您需要创建一个将显示 this 的视图MovieView带有自定义的子类可以解决问题onDraw(假设它可以访问Movie您使用前面的代码创建的)。

@Override protected void onDraw(Canvas canvas) {
    if(movie != null) {
        long now = android.os.SystemClock.uptimeMillis();
        int dur = Math.max(movie.duration(), 1); // is it really animated?
        int pos = (int)(now % dur);
        movie.setTime(pos);
        movie.draw(canvas, x, y);
    }
}

视图不会在没有帮助的情况下触发自身重绘,并且invalidate()在末尾盲目调用onDraw只是一种能量浪费。在另一个线程(可能是您用来下载图像数据的线程)中,您可以向主线程发布消息,要求视图以稳定(但不是疯狂)的速度失效。

Handler handler = new Handler();
new Thread() {
    @Override public void run() {
        // ... setup the movie (using the code from above)
        // ... create and display the custom view, passing the movie

        while(!Thread.currentThread().isInterrupted()) {
            handler.post(new Runnable() {
                public void run(){
                    view.invalidate();
                }
            });
            try {
                Thread.sleep(50); // yields 20 fps
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}.start();

一个非常好的解决方案应该有各种甜蜜的进度条和错误检查,但核心就在这里。

于 2009-05-05T06:47:29.087 回答
1

你试过了BitmapDecode吗?

此处 的 API 演示中有一个示例。

于 2009-05-02T15:38:15.403 回答
1

Glide证明了只需一行代码即可实现这一目标的最简单有效的方法:-

Glide.with(getApplicationContext())
            .load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
            .asGif().placeholder(R.drawable.ic_launcher).crossFade()
            .into(imageView);

结果在这里:-

在此处输入图像描述

Gif 取自这里http://giphy.com/search/big-gif/3

从这里添加罐子:- https://github.com/bumptech/glide/releases

于 2015-12-02T19:55:01.030 回答
0

也许AnimationDrawable可以为你工作?编辑:如果你想从像这篇文章这样的 URL 加载,则不是。对不起

http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

根据 GIF 的复杂性,即如果它是一个简单的加载/进度指示器,您可以将 GIF 分开,分别保存每个图像并使用 Android 框架的 AnimationDrawable。

对于简单的进度条,这可能不太容易出错,甚至可能更高性能。

于 2011-07-10T15:10:07.757 回答