Forum Xamarin.Android
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Android Recycler view Video Preloading / Precaching in Xamarin using Exoplayer

What I Want : When scroll to a video in recyclerview or when the video post is visible it will start playing the video instantly from the cached source. When i scrolled down it will again stop playing the video and same thing will happen for the next video in the recyclerview.

Please also suggest if there is any Xamarin Binding Library Like those avialable in Android like github.com/mobileappsvn/AutoPlayVideoRecyclerView or github.com/Krupen/AutoplayVideos

What I did : I Made a CacheVideo function and called it in the PostAdapter in OnBindViewHolder and Passed the video URI using VideCache.CacheVideosFiles(url).

I used Exoplayer for Video Playback in a Recycler view. Recylerview contains Video Posts along with other posts. I used a VideoCache Class like this - VideoCache.cs -

namespace Example.Helpers.CacheLoaders
{
public class VideoCache
{
private CacheDataSourceFactory CacheDataSourceFactory;
private static SimpleCache Cache;
private static readonly DefaultBandwidthMeter BandwidthMeter = new DefaultBandwidthMeter();
private DefaultDataSourceFactory DefaultDataSourceFac;
private Context MainContext;
public void CacheVideosFiles(Uri url)
{
try
{
MainContext = Application.Context;
Cache ??= new SimpleCache(MainContext.CacheDir, new NoOpCacheEvictor());

            CacheDataSourceFactory ??= new CacheDataSourceFactory(Cache, DefaultDataSourceFac);

            var dataSpec = new DataSpec(url, 0, 1000 * 1024, null); //0, 1000 * 1024, null
            var counters = new CacheUtil.CachingCounters();

            CacheUtil.GetCached(dataSpec, Cache, counters);

            if (counters.ContentLength == counters.TotalCachedBytes())
            {

            }
            else if (counters.TotalCachedBytes() == 0)
            {
                // not cached at all
                Task.Run(() =>
                {
                    try
                    {
                        var cacheDataSource = new CacheDataSource(Cache, CacheDataSourceFactory.CreateDataSource());
                        CacheUtil.Cache(dataSpec, Cache, cacheDataSource, counters, new AtomicBoolean());
                        double downloadPercentage = (counters.TotalCachedBytes() * 100d) / counters.ContentLength;
                        Console.WriteLine(downloadPercentage);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                });
            }
            else
            {
                // just few mb cached
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
}

}
I used this class to cache the video. I used this class in OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)

switch (itemViewType)
{ .....
case (int)PostModelType.VideoPost:
{
if (!(viewHolder is AdapterHolders.PostVideoSectionViewHolder holder))
return;

                        if (!string.IsNullOrEmpty(item.PostData.PostFileThumb))
                            FullGlideRequestBuilder.Load(item.PostData.PostFileThumb).Into(holder.VideoImage);
                        else
                            FullGlideRequestBuilder.Load(item.PostData.PostFileFull).Into(holder.VideoImage);



                       Android.Net.Uri VideoUrl = Android.Net.Uri.Parse(item.PostData.PostFileFull);
                       videoCache.CacheVideosFiles(VideoUrl);


                        break;

}
}...
And now in my custom RecyclerView

private void PlayVideo(bool isEndOfList)
{
Context context = Application.Context;
Cache ??= new SimpleCache(context.CacheDir, new NoOpCacheEvictor());

            var videoSource = GetMediaSourceFromUrl(VideoUrl, "normal");

            var dataSpec = new DataSpec(VideoUrl); //0, 1000 * 1024, null

            if (Cache == null)
                videoCache.CacheVideosFiles(VideoUrl);


            CacheDataSourceFactory ??= new CacheDataSourceFactory(Cache, DefaultDataSourceFac);

            var counters = new CacheUtil.CachingCounters();

            CacheUtil.GetCached(dataSpec, Cache, counters);
            if (counters.ContentLength == counters.TotalCachedBytes())
            {
                videoSource = new ExtractorMediaSource.Factory(CacheDataSourceFactory).CreateMediaSource(VideoUrl);
            }
            else if (counters.TotalCachedBytes() == 0)
            {
                videoSource = new ExtractorMediaSource.Factory(CacheDataSourceFactory).CreateMediaSource(VideoUrl);
                // not cached at all
                Task.Run(() =>
                {
                    try
                    {
                        var cacheDataSource = new CacheDataSource(Cache, CacheDataSourceFactory.CreateDataSource());
                        CacheUtil.Cache(dataSpec, Cache, cacheDataSource, counters, new AtomicBoolean());
                        double downloadPercentage = (counters.TotalCachedBytes() * 100d) / counters.ContentLength;
                        Console.WriteLine(downloadPercentage);
                    }
                    catch (Exception e)

Answers

Sign In or Register to comment.