I am stress testing my MonoDroid app. Each loop through the test involves giving the app a simple input, then updating the UI. I am consistently seeing the following after 97 loops through the stress test. Afterwards, the UI no longer updates:
[Surface] dequeueBuffer failed (Invalid argument)
[ViewRootImpl] Could not lock surface
[ViewRootImpl] java.lang.IllegalArgumentException
[ViewRootImpl] at android.view.Surface.nativeLockCanvas(Native Method)
[ViewRootImpl] at android.view.Surface.lockCanvas(Surface.java:243)
[ViewRootImpl] at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2435)
[ViewRootImpl] at android.view.ViewRootImpl.draw(ViewRootImpl.java:2409)
[ViewRootImpl] at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2253)
[ViewRootImpl] at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1883)
[ViewRootImpl] at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
[ViewRootImpl] at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
[ViewRootImpl] at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
[ViewRootImpl] at android.view.Choreographer.doCallbacks(Choreographer.java:574)
[ViewRootImpl] at android.view.Choreographer.doFrame(Choreographer.java:544)
[ViewRootImpl] at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
[ViewRootImpl] at android.os.Handler.handleCallback(Handler.java:733)
[ViewRootImpl] at android.os.Handler.dispatchMessage(Handler.java:95)
[ViewRootImpl] at android.os.Looper.loop(Looper.java:136)
[ViewRootImpl] at android.app.ActivityThread.main(ActivityThread.java:5017)
[ViewRootImpl] at java.lang.reflect.Method.invokeNative(Native Method)
[ViewRootImpl] at java.lang.reflect.Method.invoke(Method.java:515)
[ViewRootImpl] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
[ViewRootImpl] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
[ViewRootImpl] at dalvik.system.NativeStart.main(Native Method)
[InputMethodManager] IME died: com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME
[InputMethodManager] android.os.TransactionTooLargeException
[InputMethodManager] at android.os.BinderProxy.transact(Native Method)
[InputMethodManager] at com.android.internal.view.IInputMethodManager$Stub$Proxy.startInput(IInputMethodManager.java:604)
[InputMethodManager] at android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1173)
[InputMethodManager] at android.view.inputmethod.InputMethodManager.checkFocus(InputMethodManager.java:1282)
[InputMethodManager] at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3201)
[InputMethodManager] at android.os.Handler.dispatchMessage(Handler.java:102)
[InputMethodManager] at android.os.Looper.loop(Looper.java:136)
[InputMethodManager] at android.app.ActivityThread.main(ActivityThread.java:5017)
[InputMethodManager] at java.lang.reflect.Method.invokeNative(Native Method)
[InputMethodManager] at java.lang.reflect.Method.invoke(Method.java:515)
[InputMethodManager] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
[InputMethodManager] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
[InputMethodManager] at dalvik.system.NativeStart.main(Native Method)
Interestingly, I am NOT using any explicit surfaceView, but I do have scrollViews and a lot of RelativeLayouts.
I am curious if anyone has seen this one before, and if so, how you handled it. I did find similar crashes here and here, with a suggestion to set the layer type to software. However, in my case, setting the layer type to software merely postpones the crash slightly (98 loops instead of 97).
EDIT: Pretty much the whole App's UI is created in code, not XML. The layouts are primarily controlled by this method. The Element stuff is all custom and is unrelated to Xamarin.Forms. Basically, the app's core has computed the layout, and the front end is applying it through the method below.
public static void UpdateLayoutParamsFromModel(this View This) {
INativeElement nativeThis = This as INativeElement;
if (nativeThis != null) {
IViewParent parent = This.Parent;
if (parent == null || parent is RelativeLayout) {
IElement element = nativeThis.GetModel ();
if (element.HasLayout) {
RectangleF arranged = element.Arranged;
var layoutParams = new RelativeLayout.LayoutParams ((int)arranged.Width, (int)arranged.Height);
layoutParams.LeftMargin = (int)arranged.X;
layoutParams.TopMargin = (int)arranged.Y;
This.LayoutParameters = layoutParams;
}
}
}
FURTHER EDIT: The ScrollViews are basically my way of having ListViews without all the reloads that ListViews entail. They create their children like this. The ListViewSectionModel is a core object, which, notwithstanding the name, models an entire ListView.
public void CreateChildren() {
Android.Content.Context context = this.Context;
ListViewSectionModel model = this.Model;
int count = model.Count;
LinearLayout layout = new LinearLayout (context);
layout.SetBackgroundColor (Android.Graphics.Color.Transparent);
layout.Orientation = Orientation.Vertical;
FrameLayout.LayoutParams layoutLayoutParams = new FrameLayout.LayoutParams (FrameLayout.LayoutParams.MatchParent, FrameLayout.LayoutParams.WrapContent);
this.AddView (layout, layoutLayoutParams);
float width = model.Width;
if (width <= 0) {
CommonDebug.BreakPoint ("Need model width to create children");
}
for (int i = 0; i < count; i++) {
IElement element = model.GetElement (i);
this.HackAddOnItemClick (element, i);
float height = float.MaxValue;
SizeF childSize = new SizeF (width, height);
ElementContainerLayout child = new ElementContainerLayout (this.Context);
View childContent = child.CreateContentView (element, childSize);
float elementHeight = element.Arranged.Height;
float bigNumber = 100000;
if (elementHeight > bigNumber) {
CommonDebug.BreakPoint ("Element needs to pick a minimal height when arranging itself.");
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams (LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent);
layout.AddView (child, layoutParams);
INativeElement nativeElementChildContent = childContent as INativeElement;
if (nativeElementChildContent == null) {
CommonDebug.BreakPoint ("should be making an INativeElement.");
}
this.NativeElementChildren.Add (nativeElementChildContent);
{ // divider
View view = new View (this.Context);
view.SetBackgroundColor (Android.Graphics.Color.Gray);
LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams (LinearLayout.LayoutParams.MatchParent, 2);
layout.AddView (view, dividerParams);
}
}
}