Android: كيف يتم عرض GIF متحرك كبير إعطاء عنوان URL؟
-
03-07-2019 - |
سؤال
لنفترض أن لدي عنوان URL لـ GIF المتحركة الكبيرة وأردت أن أصنع نشاطًا يشبه YouTube الذي يعرض الرسوم المتحركة بطريقة تدفق. كيف أفعل
- دفق في الصورة؟
- احصل عليها مع الرسوم المتحركة الفعلية؟
أنا أعرف ImageView
ليس الجواب لأنه يظهر فقط الإطار الأول.
ستكون المكافأة هي الوصول إلى حالة التخزين المؤقت حتى أتمكن من مزامنة صوت البث أيضًا - هذا جزء من أ ytmnd تطبيق المشاهد. على الرغم من أنه يمكنني إنشاء خدمة تقوم بتنقل ملفات GIF العامة إلى تنسيق أجمل ، إلا أنني أود أن يعمل التطبيق دون تبعيات إضافية.
المحلول
الرسم العام للحل هو استخدام العرف 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();
الحل الجميل حقًا سيحتوي على كل أنواع أشرطة التقدم الحلو والتحقق من الأخطاء ، ولكن النواة موجودة هنا.
نصائح أخرى
هل جربت BitmapDecode
?
هناك مثال في عروض API هنا.
انسل من أثبت أكثر طريقة سهلة وفعالة لتحقيق ذلك مع سطر واحد فقط من التعليمات البرمجية:-
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
يمكن AnimationDrawable هل يمكن أن تعمل من أجلك؟ تحرير: ليس إذا كنت تريد التحميل من عنوان URL مثل هذا المنشور. آسف
http://developer.android.com/reference/android/graphics/drawable/animationDrawable.html
اعتمادًا على تعقيد GIF IE إذا كان مؤشرًا بسيطًا للتحميل/التقدم ، يمكنك تفكيك GIF عن بعضها البعض ، وإنقاذ كل صورة بشكل منفصل واستخدام Android Framework.
بالنسبة لأشرطة التقدم البسيطة ، قد يكون هذا أقل عرضة للخطأ ، وربما أكثر أداء.