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

rnd*_*lly 15 android animated-gif

假设我有大型动画gif的URL,我想创建一个像流媒体一样显示动画的youtube活动.我如何能

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

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

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

rnd*_*lly 12

解决方案的一般草图是使用雇佣习惯View,其中绘制要求a 定期Movie绘制自己Canvas.

第一步是构建Movie实例.有一个工厂叫做decodeStream可以制作一部电影,InputStream但是还不足以使用来自的电影UrlConnection.如果你试试这个,你会得到一个IOException电影加载器试图reset在流上调用.不幸的是,hack是使用一个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();
Run Code Online (Sandbox Code Playgroud)

接下来,您需要创建一个显示此视图的视图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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这种观点不会在没有帮助的情况下触发自己重新绘制,盲目地调用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();
Run Code Online (Sandbox Code Playgroud)

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