Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
CB-8139 WP8. Fix callback for plugins with native ui (capture, contac…
…tPicker, BarcodeScanner, other)

Unload event could not be used to detect when CordovaView is not used anymore. For example, this event is triggered when we execute command that shows some native elements on new page and then we return back. In this case Unloaded event is called but, but control state is preserved and we should continue to use that Cordova view instance.

This commit changes the following:
1. Allows command instances to be garbage collected => fixes corresponding memory leak so that NativeExecution is no more required to call DetachHandlers for each command. This fixes  CB-8139.
2. Use Loaded and Unloaded events to add/remove handlers for native events; this makes it possible for GC to destroy CordovaView when it is not required anymore
  • Loading branch information
sgrebnov committed Dec 15, 2014
1 parent 6bb3fc3 commit 1215509c58f6568e06aa6707e389f877513824f8
Showing 6 changed files with 75 additions and 70 deletions.
@@ -38,13 +38,6 @@ public void InjectScript()
{
}

if (!hasListener)
{
PhoneApplicationService.Current.Closing += OnServiceClosing;
hasListener = true;
}


string script = @"(function(win) {
function exec(msg) { window.external.Notify('ConsoleLog/' + msg); }
var cons = win.console = win.console || {};
@@ -71,15 +64,6 @@ void OnServiceClosing(object sender, ClosingEventArgs e)
}
}

public void DetachHandler()
{
if (hasListener)
{
PhoneApplicationService.Current.Closing -= OnServiceClosing;
hasListener = false;
}
}

public bool HandleCommand(string commandStr)
{
string output = commandStr.Substring("ConsoleLog/".Length);
@@ -96,5 +80,15 @@ public bool HandleCommand(string commandStr)
return true;
}

public void AttachNativeHandlers()
{
PhoneApplicationService.Current.Closing += OnServiceClosing;
}

public void DetachNativeHandlers()
{
PhoneApplicationService.Current.Closing -= OnServiceClosing;
}

}
}
@@ -136,21 +136,7 @@ public CordovaView()
return;
}


StartupMode mode = PhoneApplicationService.Current.StartupMode;

if (mode == StartupMode.Launch)
{
PhoneApplicationService service = PhoneApplicationService.Current;
service.Activated += new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
service.Launching += new EventHandler<LaunchingEventArgs>(AppLaunching);
service.Deactivated += new EventHandler<DeactivatedEventArgs>(AppDeactivated);
service.Closing += new EventHandler<ClosingEventArgs>(AppClosing);
}
else
{

}
Debug.WriteLine("Created new CordovaView instance");

// initializes native execution logic
configHandler = new ConfigHandler();
@@ -270,6 +256,18 @@ void AppActivated(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)

void CordovaBrowser_Loaded(object sender, RoutedEventArgs e)
{

PhoneApplicationService service = PhoneApplicationService.Current;
service.Activated += new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
service.Launching += new EventHandler<LaunchingEventArgs>(AppLaunching);
service.Deactivated += new EventHandler<DeactivatedEventArgs>(AppDeactivated);
service.Closing += new EventHandler<ClosingEventArgs>(AppClosing);

foreach (IBrowserDecorator iBD in browserDecorators.Values)
{
iBD.AttachNativeHandlers();
}


this.bmHelper.ScrollDisabled = this.DisableBouncyScrolling;

@@ -322,6 +320,20 @@ void CordovaBrowser_Loaded(object sender, RoutedEventArgs e)
}
}

private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
{
PhoneApplicationService service = PhoneApplicationService.Current;
service.Activated -= new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
service.Launching -= new EventHandler<LaunchingEventArgs>(AppLaunching);
service.Deactivated -= new EventHandler<DeactivatedEventArgs>(AppDeactivated);
service.Closing -= new EventHandler<ClosingEventArgs>(AppClosing);

foreach (IBrowserDecorator iBD in browserDecorators.Values)
{
iBD.DetachNativeHandlers();
}
}

void AttachHardwareButtonHandlers()
{
PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
@@ -524,32 +536,17 @@ public void LoadPage(string url)
}
}

private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
{
IBrowserDecorator console;
if (browserDecorators.TryGetValue("ConsoleLog", out console))
{
((ConsoleHelper)console).DetachHandler();
}

PhoneApplicationService service = PhoneApplicationService.Current;
service.Activated -= new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
service.Launching -= new EventHandler<LaunchingEventArgs>(AppLaunching);
service.Deactivated -= new EventHandler<DeactivatedEventArgs>(AppDeactivated);
service.Closing -= new EventHandler<ClosingEventArgs>(AppClosing);
}

private void CordovaBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
{
Debug.WriteLine("CordovaBrowser_NavigationFailed :: " + e.Uri.ToString());
}

private void CordovaBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
foreach(IBrowserDecorator iBD in browserDecorators.Values)
{
iBD.InjectScript();
}
foreach (IBrowserDecorator iBD in browserDecorators.Values)
{
iBD.InjectScript();
}
}

/// <summary>
@@ -576,5 +573,10 @@ protected Color ColorFromHex(string hexString)
(byte)(argb & 0xff));
return clr;
}

~CordovaView()
{
Debug.WriteLine("CordovaView is destroyed");
}
}
}
@@ -26,5 +26,7 @@ interface IBrowserDecorator
WebBrowser Browser { get; set; }
void InjectScript();
bool HandleCommand(string cmd);
void AttachNativeHandlers();
void DetachNativeHandlers();
}
}
@@ -52,21 +52,6 @@ public NativeExecution(ref WebBrowser browser)

this.webBrowser = browser;
this.commands = new List<BaseCommand>();
webBrowser.Unloaded += webBrowser_Unloaded;
}

/// <summary>
/// Detaches event handlers to prevent memory leak on page navigation
/// </summary>
void webBrowser_Unloaded(object sender, RoutedEventArgs e)
{
for (int i = commands.Count - 1; i >= 0; i--)
{
if (commands[i] != null)
{
commands[i].DetachHandlers();
}
}
}

/// <summary>
@@ -115,6 +100,12 @@ public void ProcessCommand(CordovaCommandCall commandCallParams)
return;
}

// TODO: consider removing custom script functionality at all since we already marked it as absolute (see BaseCommand)
EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
{
this.InvokeScriptCallback(script);
};

EventHandler<PluginResult> OnCommandResultHandler = delegate(object o, PluginResult res)
{
if (res.CallbackId == null || res.CallbackId == commandCallParams.CallbackId)
@@ -123,18 +114,14 @@ public void ProcessCommand(CordovaCommandCall commandCallParams)
if (!res.KeepCallback)
{
bc.RemoveResultHandler(commandCallParams.CallbackId);
bc.OnCustomScript -= OnCustomScriptHandler;
}
}
};

//bc.OnCommandResult += OnCommandResultHandler;
bc.AddResultHandler(commandCallParams.CallbackId, OnCommandResultHandler);

EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
{
this.InvokeScriptCallback(script);
};

bc.OnCustomScript += OnCustomScriptHandler;

ThreadStart methodInvokation = () =>
@@ -125,6 +125,16 @@ public bool HandleCommand(string commandStr)
// No commands are currently accepted.
return true;
}

public void AttachNativeHandlers()
{
// nothing todo
}

public void DetachNativeHandlers()
{
// nothing to do
}
}


@@ -342,5 +342,15 @@ public bool HandleCommand(string commandStr)

return false;
}

public void AttachNativeHandlers()
{
// nothing todo
}

public void DetachNativeHandlers()
{
// nothing to do
}
}
}

0 comments on commit 1215509

Please sign in to comment.