My Android Xamarin Forms App is exhibiting a 10 to 30 second lag when creating a ViewModel/View and pushing the View to the modal stack at runtime.
The application is receiving a deep link successfully, but then experiences a considerable performance lag when trying to show the desired view.
The same application executing on IOS does not have this lag.
Looking at the logs and code, the lag happens at the line I've marked with '***' below, after MT2 but before MT3 log entries.
I have been experimenting with Device.BeginInvokeOnMainThread to see if it makes the problem better or worse, but have seen no effect for this issue.
Any idea what the perf hangup might be? Is TCPOptimizer part of the problem? In case it's relevant, I've been executing the code on two different Samsung S8's.
Code
protected override async void OnAppLinkRequestReceived(Uri uri)
{
//Aside: I would rather use System.Web.HttpUtility to parse this query string, but it seems I can't in an Xam PCL.
//Pattern:
//my.app.deeplink://<command>?<params>
//Examples:
// Deep Linking Web Navigation:
// my.app.deeplink://webnav?url=/ns/products/product/?id=1234¶m1=value1¶m2=value2
// Deep Linking Native Navigation:
// my.app.deeplink://view?name=SettingsPageView¶m1=value1¶m2=value2
try
{
m_oLogging.LogInfo("OnAppLinkRequestReceived: " + uri.ToString());
NavigationManager.DeepLinkCommand oDeepCmd = NavigationManager.ParseDeepLink(uri);
switch (oDeepCmd)
{
case NavigationManager.DeepLinkCommand.invalid:
m_oLogging.LogInfo("Deep Link deemed invalid. Doing nothing.");
break;
case NavigationManager.DeepLinkCommand.webnav:
//Query expected to be like: ?url=/ns/products/product/?id=1234¶m1=value1¶m2=value2
string szUri = uri.Query;
Uri oParsedURI = WebNavigationManager.URLS.ParseDeepLinkUri(szUri);
string szURL = oParsedURI.ToString();
m_oLogging.LogInfo(string.Format("Proceeding with webnav to [{0}].", szURL));
App oApp = ((App)Application.Current);
WebNavigationManager.Instance.NavigateToURL(szURL);
break;
case NavigationManager.DeepLinkCommand.view:
//Query like: ?name=SettingsPageView¶m1=value1¶m2=value2
string szView = uri.Query.Split('=')[1].Split('&')[0];
string szViewTypeName = string.Empty;
switch (szView)
{
case "SettingsPageView":
szViewTypeName = typeof(SettingsPageView).Name;
break;
default:
//Try to dynamically present the named view.
szViewTypeName = "my.app.namespace." + szView;
break;
}
if (ViewIsAlreadyLoaded(szViewTypeName))
{
//I'm already at that page, so chill!
m_oLogging.LogInfo(string.Format("View [{0}] is already loaded in one of the stacks. No need to load it again or duplicate it.", szViewTypeName));
}
else
{
m_oLogging.LogInfo(string.Format("Proceeding with presenting view [{0}].", szViewTypeName));
switch (szView)
{
case "SettingsPageView":
//There is nothing modal right now, or there is, but the top of the stack isn't the settings page.
m_oLogging.LogInfo(string.Format("Pushing known view modally: '{0}'", szViewTypeName));
Device.BeginInvokeOnMainThread(() =>
{
m_oLogging.LogInfo(string.Format("Pushing known view modally (MT1): '{0}'", szViewTypeName));
IViewModel oSPVM = new SettingsPageViewModel();
m_oLogging.LogInfo(string.Format("Pushing known view modally (MT2): '{0}'", szViewTypeName));
*** BaseView oSPV = new SettingsPageView(oSPVM);
m_oLogging.LogInfo(string.Format("Pushing known view modally (MT3): '{0}'", szViewTypeName));
MainPage.Navigation.PushModalAsync(oSPV, false);
m_oLogging.LogInfo(string.Format("Pushed known view modally (MT4): '{0}'", szViewTypeName));
});
m_oLogging.LogInfo(string.Format("Pushed known view modally: '{0}'", szViewTypeName));
break;
default:
//Try to dynamically present the named view.
var vViewModel = Activator.CreateInstance(Type.GetType(szViewTypeName + "Model"));
if (vViewModel != null)
{
var vView = Activator.CreateInstance(Type.GetType(szViewTypeName), vViewModel);
if (vView != null)
{
m_oLogging.LogInfo(string.Format("Pushing dynamic view modally: '{0}'", szViewTypeName));
Device.BeginInvokeOnMainThread(async() => await MainPage.Navigation.PushModalAsync(vView as Page, false));
m_oLogging.LogInfo(string.Format("Pushed dynamic view modally: '{0}'", szViewTypeName));
}
}
break;
}
}
break;
}
}
catch (Exception oExc)
{
m_oLogging.LogError(oExc.Message);
}
base.OnAppLinkRequestReceived(uri);
}
Runtime Debugging content
08-01 15:14:59.023 I/MyApp (29249): OnAppLinkRequestReceived: my.package.name://view/?name=SettingsPageView&Action=Clicked 08-01 15:14:59.030 I/MyApp (29249): Proceeding with presenting view [SettingsPageView]. 08-01 15:14:59.031 I/MyApp (29249): Pushing known view modally: 'SettingsPageView' 08-01 15:14:59.031 I/MyApp (29249): Pushed known view modally: 'SettingsPageView' Thread started: #17 08-01 15:14:59.079 D/Mono (29249): [0xb7190920] worker starting 08-01 15:14:59.153 D/ViewRootImpl@3c0476fMainActivity: Relayout returned: oldFrame=[0,0][1080,2220] newFrame=[0,0][1080,2220] result=0x7 surface={isValid=true -1281830912} surfaceGenerationChanged=true 08-01 15:14:59.153 D/ViewRootImpl@3c0476fMainActivity: mHardwareRenderer.initialize() mSurface={isValid=true -1281830912} hwInitialized=true 08-01 15:14:59.162 I/MyApp (29249): Pushing known view modally (MT1): 'SettingsPageView' Resolved pending breakpoint at 'SettingsPageViewModel.cs:25,1' to bool app.namespace.name.SettingsPageViewModel.get_PreferencePushService () [0x00001]. Resolved pending breakpoint at 'SettingsPageViewModel.cs:38,1' to bool app.namespace.name.SettingsPageViewModel.get_PreferencePushDelivery () [0x00001]. Resolved pending breakpoint at 'SettingsPageViewModel.cs:51,1' to bool app.namespace.name.SettingsPageViewModel.get_PreferencePushPromotion () [0x00001]. 08-01 15:14:59.340 I/MyApp (29249): Pushing known view modally (MT2): 'SettingsPageView' 08-01 15:14:59.488 D/Mono (29249): DllImport searching in: '__Internal' ('(null)'). 08-01 15:14:59.488 D/Mono (29249): Searching for 'java_interop_jnienv_call_static_object_method'. 08-01 15:14:59.488 D/Mono (29249): Probing 'java_interop_jnienv_call_static_object_method'. 08-01 15:14:59.488 D/Mono (29249): Found as 'java_interop_jnienv_call_static_object_method'. #############################[ 3 seconds of lag ]08-01 15:15:02.826 D/TcpOptimizer(29249): [my.package.name] Full closed: sid=125, tcpi_state=8
#############################[ 1 second of lag ]08-01 15:15:03.830 D/TcpOptimizer(29249): [my.package.name] Full closed: sid=130, tcpi_state=8 Thread finished: #15 The thread 'Unknown' (0xf) has exited with code 0 (0x0).
#############################[ 26 seconds of lag ]08-01 15:15:29.177 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false 08-01 15:15:29.177 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false 08-01 15:15:29.179 I/MyApp (29249): CustomerID: (known) e3ecf5c1-3920-4cc9-ad08-0c1b2145db2b ( <-- this code runs while data is being read from the viewmodel for the view ) 08-01 15:15:29.186 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false 08-01 15:15:29.187 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false 08-01 15:15:29.188 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false 08-01 15:15:29.188 I/System.out(29249): (HTTPLog)-Static: isSBSettingEnabled false Thread started: #18 08-01 15:15:29.285 D/Mono (29249): Assembly Loader probing location: '/Users/builder/data/lanes/4009/3a62f1ea/source/monodroid/builds/install/mono-armv7/lib/app.namespace.name.resources.dll'. 08-01 15:15:29.285 D/Mono (29249): Assembly Loader probing location: '/Users/builder/data/lanes/4009/3a62f1ea/source/monodroid/builds/install/mono-armv7/lib/app.namespace.name.resources.exe'. 08-01 15:15:29.291 D/Mono (29249): Assembly Loader probing location: '/storage/emulated/0/Android/data/my.package.name/files/.override/en-US/app.namespace.name.resources.dll'. 08-01 15:15:29.364 I/MyApp (29249): Pushing known view modally (MT3): 'SettingsPageView' 08-01 15:15:29.428 W/art (29249): JNI RegisterNativeMethods: attempt to register 0 native methods for md5b60ffeb829f638581ab2bb9b1a7f4f3f.LabelRenderer 08-01 15:15:29.646 W/art (29249): JNI RegisterNativeMethods: attempt to register 0 native methods for md5b6ed58bdd2dc5ff75bde29ef5e42d6e8.ExtendedSwitchRenderer 08-01 15:15:30.001 I/MyApp (29249): Pushed known view modally (MT4): 'SettingsPageView' 08-01 15:15:30.002 I/Choreographer(29249): Skipped 1851 frames! The application may be doing too much work on its main thread. 08-01 15:15:30.111 D/ScrollView(29249): onsize change changed 08-01 15:15:30.189 D/ViewRootImpl@3c0476fMainActivity: MSG_WINDOW_FOCUS_CHANGED 1 08-01 15:15:30.189 D/ViewRootImpl@3c0476fMainActivity: mHardwareRenderer.initializeIfNeeded()#2 mSurface={isValid=true -1281830912} 08-01 15:15:30.229 V/InputMethodManager(29249): Starting input: tba=android.view.inputmethod.EditorInfo@cf0b2ac nm : my.package.name ic=null 08-01 15:15:30.230 I/InputMethodManager(29249): [IMM] startInputInner - mService.startInputOrWindowGainedFocus 08-01 15:15:30.231 D/InputTransport(29249): Input channel constructed: fd=160 08-01 15:15:30.233 D/InputMethodManager(29249): HSI from window - flag : 0 Pid : 29249 08-01 15:15:30.252 W/IInputConnectionWrapper(29249): reportFullscreenMode on inexistent InputConnection 08-01 15:15:38.190 D/Mono (29249): [0xb7190920] worker finishing Thread finished: #17 The thread 'Unknown' (0x11) has exited with code 0 (0x0). 08-01 15:15:41.995 D/TcpOptimizer(29249): [my.package.name] Full closed: sid=171, tcpi_state=8 08-01 15:15:49.902 D/ViewRootImpl@3c0476fMainActivity: MSG_RESIZED_REPORT: frame=Rect(0, 0 - 1080, 2220) ci=Rect(0, 72 - 0, 144) vi=Rect(0, 72 - 0, 144) or=1 08-01 15:15:49.972 D/ViewRootImpl@3c0476fMainActivity: Relayout returned: oldFrame=[0,0][1080,2220] newFrame=[0,0][1080,2220] result=0x1 surface={isValid=true -1281830912} surfaceGenerationChanged=false 08-01 15:15:51.378 D/ViewRootImpl@3c0476fMainActivity: MSG_WINDOW_FOCUS_CHANGED 0 08-01 15:15:54.111 D/ViewRootImpl@3c0476fMainActivity: MSG_WINDOW_FOCUS_CHANGED 1 08-01 15:15:54.111 D/ViewRootImpl@3c0476fMainActivity: mHardwareRenderer.initializeIfNeeded()#2 mSurface={isValid=true -1281830912} 08-01 15:16:09.240 D/Mono (29249): [0xbf27c920] worker finishing Thread finished: #10 The thread 'Unknown' (0xa) has exited with code 0 (0x0).
Any assistance is appreciated!