Android:如何在给定网址的情况下显示大型动画 gif? [英] Android: How do a display a large animated gif given a url?

查看:31
本文介绍了Android:如何在给定网址的情况下显示大型动画 gif?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Suppose I have the URL for large animated gif and I wanted to make a youtube like activity that displays the animation in a streaming way. How do I

  1. 在图像中流式传输?
  2. 让它以实际动画显示?

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

I know ImageView is not the answer as it only shows the first frame.

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

A bonus would be having access to its buffering status so I can synchronize streaming sound as well -- this is part of a YTMND viewer application. While I could create a service that transcodes the public gif files into a nicer format, I'd like the app to function without additional dependencies.

推荐答案

解决方案的总纲是使用应用自定义View绘制要求Movie绘制自己定期到 Canvas.

The general sketch of the solution is to use employ custom View which draws asks a Movie to draw itself to the Canvas periodically.

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

The first step is building the Movie instance. There is factory called decodeStream that can make a movie given an InputStream but it isn't enough to use the stream from a UrlConnection. If you try this you will get an IOException when the movie loader tries to call reset on the stream. The hack, unfortunate as it is, is to use a separated BufferedInputStream with a manually-set mark to tell it to save enough data that reset won't fail. Luckily, the URLConnection can tell us how much data to expect. I say this hack is unfortunate because it effectively requires the entire image to be buffered in memory (which is no problem for desktop apps, but it is a serious issue on a memory-constrained mobile device).

这里是 Movie 设置代码的片段:

Here is a snip of the Movie setup code:

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();

接下来,您需要创建一个视图来显示此Movie.带有自定义 onDrawView 子类将起到作用(假设它可以访问您使用先前代码创建的 Movie).

Next, you need to create a view that will display this Movie. A subclass of View with a custom onDraw will do the trick (assuming it has access to the Movie you created with the previous code).

@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);
    }
}

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

The view won't trigger itself to be redrawn without help, and blindly calling invalidate() at the end of onDraw is just an energy waste. In another thread (probably the one you used to download the image data), you can post messages to the main thread, asking for the view to be invalidated at a steady (but not insane) pace.

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();

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

A really nice solution would have all sorts of sweet progress bars and error checking, but the core is here.

这篇关于Android:如何在给定网址的情况下显示大型动画 gif?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆