عند إنشاء تطبيق يحتوي على فيديوهات متتالية مثل TikTok أو Instagram Reels أو YouTube Shorts، فإن تحميل عدد كبير من الفيديوهات في نفس الوقت قد يؤدي إلى استهلاك كبير للذاكرة، وتأخير في تشغيل الفيديو، ومشاكل أثناء التمرير السريع.
هنا تأتي حزمة video_flux، وهي حزمة مخصصة لإدارة وتحسين عملية Video Preloading داخل تطبيقات Flutter، من خلال الاحتفاظ بعدد محدود من الـ controllers حول الفيديو النشط بدلًا من تحميل جميع الفيديوهات الموجودة في القائمة.
ما هي حزمة video_flux؟
حزمة video_flux هي player-agnostic video preloader، أي أنها لا تعتمد على مشغل فيديو محدد ولا تقوم بتشغيل الفيديو بنفسها.
وظيفتها الأساسية هي إنشاء وإدارة الـ controllers، والإبقاء على مجموعة محدودة منها جاهزة حول العنصر الحالي، ثم التخلص من الـ controllers التي تخرج من نطاق التحميل.
وهذا يجعلها مناسبة جدًا لتطبيقات الـ feeds التي تحتوي على فيديوهات متتابعة ويحتاج المستخدم فيها إلى انتقال سريع من فيديو إلى آخر.
لماذا نحتاج إلى Video Preloading؟
لنفترض أن لدينا Feed يحتوي على 100 فيديو، وقمنا بإنشاء controller لكل فيديو منذ البداية.
Video 1
Video 2
Video 3
...
Video 100
هذا الأسلوب قد يستهلك قدرًا كبيرًا من الذاكرة والموارد، خصوصًا عند استخدام فيديوهات عالية الجودة.
بدلًا من ذلك يمكننا الاحتفاظ مثلًا بالفيديو الحالي، وفيديوهين قبله، وفيديوهين بعده فقط.
Previous Previous Current Next Next
🎬 🎬 ▶️ 🎬 🎬
عندما ينتقل المستخدم إلى الفيديو التالي، تتحرك هذه النافذة ويتم التخلص من الفيديوهات التي أصبحت بعيدة وإنشاء controllers للفيديوهات الجديدة.
مميزات video_flux
- Sliding Window Preloading لتحميل الفيديوهات القريبة من الفيديو الحالي فقط.
- دعم أي Video Player تقريبًا من خلال Adapter بسيط.
- تقليل العمليات أثناء التمرير السريع من خلال Debounce.
- تحديد عدد عمليات Initialize التي تعمل في نفس الوقت.
- التخلص من الـ controllers القديمة قبل إنشاء الجديدة لتقليل ذروة استهلاك الذاكرة.
- التكيف مع إمكانيات الجهاز وضغط الذاكرة.
- دعم Retry للفيديوهات التي فشل تحميلها.
- دعم Pagination لجلب فيديوهات إضافية عند الاقتراب من نهاية القائمة.
- دعم Refresh واستبدال عناصر الـ Feed بدون إعادة إنشاء كل شيء من البداية.
- إحصائيات وتشخيصات لمعرفة أداء عملية التحميل.
- لا تعتمد على Bloc أو Riverpod أو Provider أو GetX.
إضافة الحزمة إلى مشروع Flutter
الإصدار الموجود حاليًا على pub.dev هو 0.0.1.
أضف الحزمة إلى ملف pubspec.yaml:
dependencies:
video_flux: ^0.0.1
video_player: latest_version
الميزة المهمة هنا أن video_flux لا يفرض عليك Video Player معين، ويمكنك استخدام video_player أو أي مشغل آخر يدعم العقد المطلوب.
الفكرة الأساسية في video_flux
الحزمة تعتمد على مفهوم يسمى Sliding Window.
مثلًا يمكن ضبط الإعدادات لتحتفظ بفيديوين قبل الفيديو الحالي وفيديوين بعده:
const config = VideoFluxConfig(
preloadBackward: 2,
preloadForward: 2,
windowSize: 5,
);
بهذا الشكل تصبح النافذة تقريبًا:
2 Previous + 1 Current + 2 Next = 5 Controllers
كلما تغير الفيديو النشط يتم نقل النافذة إلى الموقع الجديد.
إنشاء Adapter لـ video_player
لأن video_flux لا يرتبط بمشغل معين، نحتاج إلى إنشاء Adapter يربط بين الحزمة ومشغل الفيديو الذي نستخدمه.
import 'package:video_flux/video_flux.dart';
import 'package:video_player/video_player.dart';
class VideoPlayerAdapter extends CustomVideoController {
VideoPlayerAdapter(this.dataSource)
: player = VideoPlayerController.networkUrl(
Uri.parse(dataSource),
);
@override
final String dataSource;
final VideoPlayerController player;
@override
bool get isInitialized => player.value.isInitialized;
@override
bool get isPlaying => player.value.isPlaying;
@override
Future<void> initialize() {
return player.initialize();
}
@override
Future<void> play() {
return player.play();
}
@override
Future<void> pause() {
return player.pause();
}
@override
Future<void> dispose() {
return player.dispose();
}
@override
Future<void> warmUp() async {
await player.seekTo(Duration.zero);
await player.pause();
}
}
هذه هي الطبقة التي تجعل video_flux يعرف كيف ينشئ الفيديو ويقوم بتهيئته وتشغيله وإيقافه والتخلص منه.
إنشاء Model للفيديو
كل عنصر داخل الـ Feed يجب أن يحتوي على id ثابت وفريد بالإضافة إلى رابط الفيديو.
class FeedVideo implements VideoFluxItem {
const FeedVideo({
required this.id,
required this.url,
});
@override
final String id;
@override
final String url;
}
وجود ID ثابت مهم جدًا لأن الحزمة تعتمد عليه في عمليات البحث والتنقل والاستبدال، وليس على الـ index فقط.
إنشاء VideoFlux
final preloader = VideoFlux<FeedVideo>(
items: videos,
controllerFactory: VideoPlayerAdapter.new,
config: const VideoFluxConfig.tikTok(),
onControllerInitialized: (controller) {
setState(() {});
},
onControllerInitializationError: (
controller,
error,
stackTrace,
) {
debugPrint(error.toString());
},
);
هنا قمنا بتمرير قائمة الفيديوهات، وFactory لإنشاء الـ controllers، بالإضافة إلى إعدادات مناسبة لفيديوهات الـ Feed.
استخدام PageView مع video_flux
تستطيع استخدام PageView لإنشاء Feed عمودي مشابه لتطبيقات الفيديو القصيرة.
PageView.builder(
scrollDirection: Axis.vertical,
itemCount: preloader.itemCount,
onPageChanged: (index) {
preloader.scroll(index);
},
itemBuilder: (context, index) {
return FeedPage(
index: index,
);
},
);
عند تغير الصفحة نقوم فقط باستدعاء:
preloader.scroll(index);
والحزمة تتولى تحريك الـ window، وإيقاف الفيديوهات الأخرى، وتجهيز الفيديو الجديد.
عرض الفيديو الحالي
عند بناء الواجهة يمكننا الحصول على الـ controller من خلال الـ index:
final controller =
preloader.getControllerAtIndex(index);
if (controller == null ||
!controller.isInitialized) {
return const Center(
child: CircularProgressIndicator(),
);
}
return VideoPlayer(
(controller as VideoPlayerAdapter).player,
);
من المهم معرفة أن إرجاع null لا يعني وجود خطأ بالضرورة، فقد يكون الفيديو خارج الـ window أو لم تنته عملية تهيئته بعد.
لا تقم بعمل dispose للـ controller داخل Widget
هذه نقطة مهمة جدًا عند استخدام video_flux.
الـ controller تتم إدارته بواسطة الـ preloader، ولذلك لا يجب أن تقوم الـ Widget التي تعرض الفيديو بعمل dispose() له.
بدلًا من ذلك يقوم scroll() بإيقاف الفيديوهات غير النشطة، بينما يتم التخلص من الـ controllers التي خرجت من الـ window.
التخلص من الموارد
عند انتهاء الشاشة أو إزالة الـ Feed بالكامل، يجب التخلص من جميع الـ controllers:
@override
void dispose() {
preloader.disposeAll();
super.dispose();
}
هذه الخطوة مهمة لأن مشغلات الفيديو تستخدم Native Decoders ولا يكفي الاعتماد على Garbage Collection فقط.
إعدادات جاهزة لـ TikTok و Shorts
الحزمة توفر Presets جاهزة لبعض أنواع الـ feeds.
TikTok Feed
const VideoFluxConfig.tikTok()
الإعداد الافتراضي يحتفظ بفيديو واحد خلف الفيديو الحالي وفيديوهين أمامه، بإجمالي Window بحجم 4.
Shorts Feed
const VideoFluxConfig.shorts()
هذا الـ preset يحتفظ بفيديوهين خلف الفيديو الحالي وفيديوهين أمامه، مع Window بحجم 5.
Current Only
const VideoFluxConfig.currentOnly()
وهذا مناسب للأجهزة شديدة المحدودية أو عندما تريد الاحتفاظ بالفيديو الحالي فقط.
تقليل المشاكل أثناء التمرير السريع
أحد الأشياء المميزة في video_flux هو التعامل مع التمرير السريع.
عندما يقوم المستخدم بالسحب بسرعة عبر عدد كبير من الفيديوهات، لا تريد أن تبدأ عملية تحميل لكل فيديو مرّ عليه المستخدم.
الحزمة تستخدم scroll debounce لتجميع تغييرات الـ index، وتضع حدًا لعدد عمليات initialization المتزامنة.
الإعداد الافتراضي هو:
scrollDebounce: Duration(milliseconds: 120)
maxConcurrentInitializations: 2
كما أن القفز إلى مسافة كبيرة يتجاوز الـ debounce حتى يبدأ الفيديو الذي ينتظر المستخدم الوصول إليه بسرعة.
Direction و Velocity Preloading
يمكن جعل التحميل المسبق أكثر ذكاءً من خلال معرفة اتجاه وسرعة التمرير.
const config = VideoFluxConfig(
preloadBackward: 2,
preloadForward: 2,
windowSize: 5,
directionalPreloadBias: 1,
maxVelocityPreload: 2,
velocityPreloadThreshold: 1,
);
وبعد ذلك يمكن إرسال سرعة التمرير:
await preloader.scroll(
pageIndex,
scrollVelocity: pagesPerSecond,
);
وبذلك يمكن إعطاء أولوية للفيديوهات الموجودة في الاتجاه الذي يتحرك إليه المستخدم.
Adaptive Memory Management
من أهم المميزات أن الحزمة تستطيع تعديل حجم الـ window حسب إمكانيات الجهاز وضغط الذاكرة.
هناك ثلاث مستويات تقريبية للأجهزة:
- Low: تحميل محدود جدًا.
- Mid: Window متوسطة.
- High: استخدام الإعدادات التي حددها المطور.
كما يمكن للحزمة تقليل عدد الـ controllers عند وجود Memory Pressure، ثم العودة تدريجيًا إلى الحدود السابقة بعد استقرار الوضع.
يمكن أيضًا إرسال مستوى الضغط يدويًا:
preloader.reportMemoryPressure(
MemoryPressureLevel.moderate,
);
Pagination مع الفيديوهات
إذا كان لديك Feed يتم تحميله على صفحات، تستطيع جعل الحزمة تطلب الصفحة التالية عندما يقترب المستخدم من نهاية القائمة.
final preloader = VideoFlux<FeedVideo>(
items: firstPage,
controllerFactory: VideoPlayerAdapter.new,
onPaginationNeeded: () {
return api.fetchNextPage();
},
onPaginationError: (error, stackTrace) {
debugPrint(error.toString());
},
);
يمكنك تحديد متى يبدأ طلب الصفحة الجديدة باستخدام:
paginationThreshold: 5
أي عندما يتبقى عدد محدد من العناصر يبدأ الـ preloader بطلب الصفحة التالية.
Retry عند فشل تحميل الفيديو
في حال فشل تحميل فيديو، تستطيع إعادة المحاولة بدلًا من ترك المستخدم أمام مؤشر تحميل لا نهائي.
await preloader.retry(index);
كما توفر الحزمة سياسات Retry جاهزة، منها Exponential Backoff وFixed Delay، ويمكنك أيضًا إنشاء سياسة خاصة بك.
Refresh بدون إنشاء Preloader جديد
عند تنفيذ Pull to Refresh لا تحتاج إلى إنشاء كائن VideoFlux جديد.
await preloader.replaceItems(
freshVideos,
);
إذا كان الفيديو لا يزال موجودًا بنفس id وurl وفي نطاق الـ window، تستطيع الحزمة الاحتفاظ بالـ controller الجاهز بدل تهيئته من جديد.
الحصول على الفيديو باستخدام ID
يمكنك أيضًا التعامل مع الفيديوهات باستخدام ID بدل الاعتماد دائمًا على الـ index:
await preloader.scrollToId(videoId);
final video =
preloader.getItemById(videoId);
final controller =
preloader.getControllerById(videoId);
هذه الطريقة مفيدة جدًا عندما تتغير ترتيب العناصر داخل الـ Feed أو عند التعامل مع تحديثات البيانات.
Diagnostics ومراقبة الأداء
توفر الحزمة إحصائيات مدمجة يمكن استخدامها لفهم أداء الـ preloader:
print(preloader.stats);
ومن المعلومات التي يمكنك مراقبتها عدد الـ controllers النشطة، وعدد عمليات التحميل الملغاة، وعدد العناصر التي تم تحريرها، ونسبة الاستفادة من الـ window، بالإضافة إلى زمن التهيئة.
وجود هذه البيانات مفيد جدًا أثناء تحسين تطبيقات الفيديو والتأكد من أن حجم الـ window مناسب للأجهزة المستهدفة.
هل video_flux يقوم بتخزين ملفات الفيديو؟
لا.
الحزمة لا تقوم بعمل Byte Cache لملفات الفيديو نفسها، وإنما تحتفظ بالـ controllers التي تم تهيئتها حول الفيديو النشط.
إذا كان مشروعك يحتاج إلى تخزين الفيديوهات أو HTTP caching، فيمكنك استخدام نظام Cache مستقل أو Video Player يدعم التخزين المؤقت.
مناسب لأي نوع من التطبيقات؟
يمكن استخدام video_flux في التطبيقات التي تعتمد بشكل كبير على الفيديوهات المتتابعة، مثل:
- TikTok Style Feed
- Instagram Reels Style Feed
- YouTube Shorts
- Video Stories
- Social Media Video Feed
- أي قائمة تتحرك بين فيديوهات متتابعة
مميزات الحزمة مقارنة باستخدام Video Player وحده
مشغل مثل video_player يعطيك أدوات تشغيل الفيديو، لكنه لا يحل وحده مشكلة إدارة عدد كبير من الـ controllers داخل Feed سريع.
أما video_flux فيضيف طبقة لإدارة هذه الـ controllers من خلال Window محددة، وترتيب عمليات التهيئة، وإيقاف العناصر غير النشطة، والتعامل مع الـ memory pressure والـ retry والـ pagination.
الخلاصة
إذا كنت تعمل على تطبيق Flutter يحتوي على Feed من الفيديوهات وتريد تجربة تمرير سلسة دون إنشاء عشرات الـ controllers في نفس الوقت، فإن video_flux يقدم فكرة عملية جدًا تعتمد على Sliding Window Video Preloading.
الميزة الأهم في الحزمة أنها لا تجبرك على Video Player معين، بل تركز فقط على إدارة دورة حياة الـ controllers وتحسين عملية الـ preload، وبالتالي يمكنك دمجها مع البنية الحالية لمشروعك واختيار مشغل الفيديو الذي يناسبك.
وبفضل دعمها للـ adaptive memory limits والـ fast scrolling والـ pagination والـ retry والـ diagnostics، يمكن أن تكون خيارًا مناسبًا جدًا لبناء Video Feeds حديثة في Flutter.
عنوان المقال: video_flux في Flutter لتحسين تحميل الفيديوهات أثناء التمرير
الوصف: شرح حزمة video_flux في Flutter لتحسين تحميل الفيديوهات في تطبيقات مثل TikTok وReels، مع Sliding Window وPreloading وتقليل استهلاك الذاكرة ودعم Pagination وRetry.
الكلمة المفتاحية: Flutter Video Preloading
الرابط المقترح: video-flux-flutter-video-preloading
كلمات مفتاحية إضافية: Flutter Video Feed, Video Preloading Flutter, Flutter Video Player, TikTok Feed Flutter, Flutter Reels, Video Caching Flutter, Flutter Performance
صفحة حزمة video_flux الرسمية على pub.dev
[1]: https://pub.dev/packages/video_flux “video_flux | Flutter package”
مزيد من المقالات : اكثر اكواد بايثون استخداما للمبتدئين python code






