解決策の一般的なスケッチは、定期的に描画View
するように要求するカスタムを使用することです。Movie
Canvas
最初のステップは、Movie
インスタンスを構築することです。decodeStream
与えられた映画を作ることができると呼ばれる工場がありますがInputStream
、からのストリームを使用するのに十分ではありませんUrlConnection
。これを試してみるとIOException
、ムービーローダーreset
がストリームを呼び出そうとしたときに取得できます。ハックは、残念ながらBufferedInputStream
、手動で設定されたセパレートを使用して、失敗しないmark
十分なデータを保存するように指示することです。reset
幸いなことに、はURLConnection
どのくらいのデータを期待できるかを教えてくれます。このハックは、画像全体をメモリに効果的にバッファリングする必要があるため、残念なことです(デスクトップアプリでは問題ありませんが、メモリに制約のあるモバイルデバイスでは深刻な問題です)。
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();
次に、これを表示するビューを作成する必要があります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);
}
}
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();
本当に素晴らしいソリューションには、あらゆる種類の甘いプログレスバーとエラーチェックがありますが、コアはここにあります。