Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot access a disposed object: Android.Webkit.WebView #6

Open
casas333 opened this issue May 5, 2020 · 2 comments
Open

Cannot access a disposed object: Android.Webkit.WebView #6

casas333 opened this issue May 5, 2020 · 2 comments

Comments

@casas333
Copy link

casas333 commented May 5, 2020

Steps to reproduce:

  1. Have 3+ ContentViews each with a HibridWebViewControl component
  2. Add some buttons to change the content views in the page to navigate through the webviews
  3. Navigate fast from contentView1 to contentView3 to show the last webview passing over the others.

expected: last webview is shown, no crashes

current:

Cannot access a disposed object.
Object name: 'Android.Webkit.WebView'.
at Java.Interop.JniPeerMembers.AssertSelf (Java.Interop.IJavaPeerable self) [0x00029] in <26521a5118b44c858c385715922b9d5d>:0
at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00000] in <26521a5118b44c858c385715922b9d5d>:0
at Android.Webkit.WebView.get_Url () [0x0000a] in <4ccdb3137d974856b786e1aeebbfbab6>:0
at Plugin.HybridWebView.Droid.HybridWebViewRenderer.b__35_0 () [0x0000c] in <2f2d06da51e84164a0ac7ab59cb79a28>:0
at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <4ccdb3137d974856b786e1aeebbfbab6>:0
at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00009] in <4ccdb3137d974856b786e1aeebbfbab6>:0
at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.44(intptr,intptr)

I use the webview in an own VideoPlayer component to reproduce video:

public sealed class VideoPlayer : Grid, IDisposable
{
    private HybridWebViewControl _webPlayer;


    public static readonly BindableProperty VideoUrlProperty = BindableProperty.Create(nameof(VideoUrl), typeof(Uri), typeof(VideoPlayer), null, BindingMode.TwoWay);
    

    public Uri VideoUrl
    {
        get => (Uri) GetValue(VideoUrlProperty);
        set => SetValue(VideoUrlProperty, value);
    }

    public static readonly BindableProperty AutoPlayProperty = BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(VideoPlayer), false, BindingMode.TwoWay);

    public bool AutoPlay
    {
        get => (bool)GetValue(AutoPlayProperty);
        set => SetValue(AutoPlayProperty, value);
    }

    public static readonly BindableProperty VideoLoadedCommandProperty = BindableProperty.Create(nameof(VideoLoadedCommand), typeof(ICommand), typeof(VideoPlayer));
    public ICommand VideoLoadedCommand
    {
        get => (ICommand)GetValue(VideoLoadedCommandProperty);
        set => SetValue(VideoLoadedCommandProperty, value);
    }

    public VideoPlayer()
    {
        _webPlayer = new HybridWebViewControl
        {
            BackgroundColor = Color.Transparent,
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };
        Children.Add(_webPlayer);

        _webPlayer.OnNavigationCompleted += WebPlayer_Navigated;

        VideoLoadedCommand = new Command(OnVideoLoaded);
    }

    public void OnVideoLoaded()
    {
        if (AutoPlay)
        {
            Play();
        }
    }

    public void Play()
    {
        _webPlayer.InjectJavascriptAsync("document.getElementsByTagName('video')[0].play();");
    }

    public void Pause()
    {
        _webPlayer.InjectJavascriptAsync("document.getElementsByTagName('video')[0].pause();");
    }

    private void WebPlayer_Navigated(object sender, string e)
    {
        _webPlayer.InjectJavascriptAsync(@"document.getElementsByTagName('video')[0].pause();
                    document.getElementsByTagName('video')[0].style.backgroundColor='transparent';
                    document.getElementsByTagName('video')[0].style.width='100%';
                    document.getElementsByTagName('body')[0].style.backgroundColor='transparent';");

        VideoLoadedCommand?.Execute(null);
    }

    public void OpenVideo(object sender = null, EventArgs e = null)
    {
        Children.Remove(_webPlayer);
        Children.Add(_webPlayer);

        _webPlayer.Source = VideoUrl.AbsoluteUri;
        _webPlayer.HorizontalOptions = LayoutOptions.FillAndExpand;
        _webPlayer.VerticalOptions = LayoutOptions.FillAndExpand;
    }

    public void CloseVideo(object sender = null, EventArgs e = null)
    {
        Dispose();
    }

    public void Dispose()
    {
        try
        {
            _webPlayer.OnNavigationCompleted -= WebPlayer_Navigated;
            Children.Clear();                
            _webPlayer?.Dispose();
            _webPlayer = null;                
        }
        catch (Exception exception)
        {
            Debug.WriteLine(exception.Message+exception.StackTrace);
        }
    }
}

Maybe the solution proposed here can be helpful:

xamarin/Xamarin.Forms#6286

@stoff99
Copy link

stoff99 commented May 7, 2020

Hello @candidodmv ,

can you have a short looks on it?

Thx Stefan

@candidodmv
Copy link
Contributor

I'll checkout this ASP, let's try just unbind the event on dispose as referred by @casas333 above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants