Android:如何在给定网址的情况下显示大型动画 gif?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/809878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:26:18  来源:igfitidea点击:

Android: How do a display a large animated gif given a url?

androidanimated-gif

提问by rndmcnlly

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

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

  1. stream in the image?
  2. get it do display with actual animation?
  1. 在图像中流?
  2. 让它以实际动画显示?

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

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

A bonus would be having access to its buffering status so I can synchronize streaming sound as well -- this is part of a YTMNDviewer 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.

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

采纳答案by rndmcnlly

The general sketch of the solution is to use employ custom Viewwhich draws asks a Movieto draw itself to the Canvasperiodically.

解决方案的一般草图是使用View绘制请求的自定义绘制周期性地Movie绘制自身Canvas

The first step is building the Movieinstance. There is factory called decodeStreamthat can make a movie given an InputStreambut it isn't enough to use the stream from a UrlConnection. If you try this you will get an IOExceptionwhen the movie loader tries to call reseton the stream. The hack, unfortunate as it is, is to use a separated BufferedInputStreamwith a manually-set markto tell it to save enough data that resetwon't fail. Luckily, the URLConnectioncan 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实例。有一个工厂叫做decodeStream可以制作给定的电影,InputStream但使用来自 的流是不够的UrlConnection。如果您尝试此操作,您将IOException在电影加载器尝试调用reset流时得到一个。不幸的是,hack 是使用一个BufferedInputStream带有手动设置的分隔符mark来告诉它保存足够多的reset不会失败的数据。幸运的是,它URLConnection可以告诉我们需要多少数据。我说这个 hack 很不幸,因为它实际上需要将整个图像缓冲在内存中(这对于桌面应用程序来说没有问题,但在内存受限的移动设备上却是一个严重的问题)。

Here is a snip of the Moviesetup code:

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

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

接下来,您需要创建一个将显示此Movie. 一个View带有自定义的子类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);
    }
}

The view won't trigger itself to be redrawn without help, and blindly calling invalidate()at the end of onDrawis 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.

视图不会在没有帮助的情况下触发自身重绘,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();

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

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

回答by JRL

Did you try BitmapDecode?

你试了BitmapDecode吗?

There's an example in the API Demos here.

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

回答by Hitesh Sahu

Glideprove most easy and efficient way to achieve this with just one line of code :-

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

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

Result is here :-

结果在这里:-

enter image description here

在此处输入图片说明

Gif taken from here http://giphy.com/search/big-gif/3

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

Add jar from here :- https://github.com/bumptech/glide/releases

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

回答by concept

Maybe AnimationDrawablecould work for you? EDIT: Not if you want to load from a URL like this post is about. Sorry

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

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

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

Depending on the complexity of the GIF i.e. if it is a simple loading/progress indicator you could break the GIF apart, save each image separately and use the Android Framework's AnimationDrawable.

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

For simple progress bars this may be less error prone, maybe even more performant.

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