具有异步/等待图像加载的自定义MvxAdapter

时间:2014-08-08 12:12:13

标签: android youtube-api xamarin async-await mvvmcross

我正在尝试创建填充了youtube视频缩略图的GridView。

我使用异步任务模式类

包装了YouTubeThumbnailLoader
interface IThumbnailLoader
{
    Task<Drawable> LoadVideoThumbnailAsync(string id);
}   

/// <summary>
/// Class to load youtube stuff
/// </summary>
class YoutubeThumbnailLoader : Java.Lang.Object, YouTubeThumbnailView.IOnInitializedListener, IThumbnailLoader
{
    private YouTubeThumbnailView thumbnailView;
    private IYouTubeThumbnailLoader thumbnailLoader;

    TaskCompletionSource<IYouTubeThumbnailLoader> _tcsLoaderInitializated;

    public YoutubeThumbnailLoader()
    {
        _tcsLoaderInitializated = new TaskCompletionSource<IYouTubeThumbnailLoader>();
    }

    public async Task InitializeAsync(Context context)
    {
        ...
    }

    public async Task<Drawable> LoadVideoThumbnailAsync(string id)
    {
        try
        {
            MvxTrace.TaggedTrace("YoutubeThumbnailLoader.LoadVideoThumbnailAsync", "Started load task for id {0}", id);

            TaskCompletionSource<Drawable> tcsImageLoaded = new TaskCompletionSource<Drawable>();
            //TODO: unsure about that
            thumbnailLoader.SetOnThumbnailLoadedListener(null);
            thumbnailLoader.SetOnThumbnailLoadedListener(new ThumbnailListener(this, tcsImageLoaded));

            string fid = ClearUrl(id);
            thumbnailLoader.SetVideo(fid);

            return await tcsImageLoaded.Task.ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            MvxTrace.Trace(ex.ToString());
            throw;
        }            
    }

    private string ClearUrl(string id)
    {
        ...
    }

    ~YoutubeThumbnailLoader()
    {
        if (thumbnailLoader != null)
        {
            thumbnailLoader.Release();
        }
    }

    public void OnInitializationFailure(YouTubeThumbnailView thumbnailView, YouTubeInitializationResult errorReason)
    {
        ...
    }

    public void OnInitializationSuccess(YouTubeThumbnailView p0, IYouTubeThumbnailLoader thumbnailLoader)
    {
        ...
    }

    /// <summary>
    ///  An internal listener which listens to thumbnail loading events from the
    /// YouTubeThumbnailView.
    /// </summary>
    private sealed class ThumbnailListener : Java.Lang.Object, IYouTubeThumbnailLoaderOnThumbnailLoadedListener
    {
        private YoutubeThumbnailLoader youtubeThumbnailLoader;
        private TaskCompletionSource<Drawable> tcs;

        public ThumbnailListener(YoutubeThumbnailLoader youtubeThumbnailLoader, TaskCompletionSource<Drawable> tcsImageLoaded)
        {
            this.youtubeThumbnailLoader = youtubeThumbnailLoader;
            this.tcs = tcsImageLoaded;
        }

        public void OnThumbnailError(YouTubeThumbnailView thumbnail, YouTubeThumbnailLoaderErrorReason reason)
        {
            MvxTrace.Trace("Thumbnail listener Error: " + reason.ToString());
            tcs.SetException(new YoutubeThumbnailException(reason));
        }

        public void OnThumbnailLoaded(YouTubeThumbnailView thumbnail, string videoId)
        {
            MvxTrace.Trace("Thumbnail listener loaded: " + videoId);
            tcs.SetResult(thumbnail.Drawable);
        }
    }

    internal async static Task<IThumbnailLoader> CreateLoader(Context context)
    {
        var me = new YoutubeThumbnailLoader();
        await me.InitializeAsync(context);
        return me;
    }
}

当我使用这个类来填充简单的'ImageView'时,效果很好:

public override async void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        var ld = await YoutubeThumbnailLoader.CreateLoader(this.Activity);

        _iv.SetImageDrawable(await ld.LoadVideoThumbnailAsync("sFSesoqjNn8"));
        _iv2.SetImageDrawable(await ld.LoadVideoThumbnailAsync("sFSesoqjNn8"));

        _gridView.Adapter = new Adapters.CustomGridViewAdapter(ld, Activity, (IMvxAndroidBindingContext)BindingContext);

    }

但在我的自定义适配器中它根本不起作用。这是

class CustomGridViewAdapter : MvxAdapter
{
    private Helpers.IThumbnailLoader _ytl;
    public CustomGridViewAdapter(Helpers.IThumbnailLoader ytl, Context context, IMvxAndroidBindingContext bindingContext)
            : base(context, bindingContext)
        {
            _ytl = ytl;
        }        

    async Task SetImageView(string id, ImageView iv)
    {
        var dr = await _ytl.LoadVideoThumbnailAsync(id);
        MvxTrace.TaggedTrace("CustomGridViewAdapter.GetView", "loaded some item {0}", dr.ToString());
        iv.SetImageDrawable(dr);
    }


    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        LayoutInflater inflater = ((Activity)base.Context).LayoutInflater;
        var rowView = inflater.Inflate(Resource.Layout.item_video_wall, parent, false);
        ImageView imageView = rowView.FindViewById<ImageView>(Resource.Id.imageView1);

        var bb = (YouTubeVideoTag)GetRawItem(position);

        MvxTrace.TaggedTrace("CustomGridViewAdapter.GetView", "Prepared to load '{0}' item into position {1}", bb.VideoUrl, position);

        SetImageView(bb.VideoUrl, imageView);

        return rowView;
    }

我认为这个调用应该保存当前的'ImageView'指针并将其设置为可绘制的,但这不起作用,我不明白为什么。

SetImageView(bb.VideoUrl, imageView);

任何帮助?

1 个答案:

答案 0 :(得分:0)

问题在于

TaskCompletionSource<Drawable> tcsImageLoaded = new TaskCompletionSource<Drawable>();

//TODO: unsure about that
thumbnailLoader.SetOnThumbnailLoadedListener(null);
thumbnailLoader.SetOnThumbnailLoadedListener(new ThumbnailListener(this, tcsImageLoaded));

我甚至在任务完成之前替换了听众。 我重写了这段代码并为每个GridView项目

创建了加载器
if (holder.Image != null)
{
    var bb = (YouTubeVideoTag)GetRawItem(position);
    MvxTrace.TaggedTrace("CustomGridViewAdapter.GetView", "Prepared to load '{0}' item into position {1}", bb.VideoUrl, position);
    (new ImageSetAsyncWorker(base.Context, holder.Image)).SetImageView(bb.VideoUrl);
}

我不确定这是使用YouTubeThumbnailLoader的正确方法,但它有效。

public async Task SetImageView(string id)
{
    var loader = await Helpers.YoutubeThumbnailLoader.CreateLoader(_context);

    var dr = await loader.LoadVideoThumbnailAsync(id);
    MvxTrace.TaggedTrace("CustomGridViewAdapter.GetView", "loaded some item {0}", dr.ToString());
    ImageView iv;
    if (_wr.TryGetTarget(out iv))
    {
        iv.SetImageDrawable(dr);
    }
}