Search code examples
xamarinbindingxamarin.androidlinkermvvmcross

MvvmCross Android binding EditText in release mode


I have a problem with binding EditText on Android platform. Today I update in my project MvvmCross framework from 6.2.X to 6.3.1 (+ update others NuGets) and changed TargetSdk and CompileSdk from Android 8.1 to 9.0 and now when I have Release mode and linking set to "Sdk Assemblies" Only my app crash on View where I have binding EditText. In debug where I have checked "Use Shared Runtime" and set linking to "None" there is no problem it works.

I have Include TextView in LinkerPleaseInclude:

public void Include(TextView text)
{
    text.AfterTextChanged += (sender, args) => text.Text = $"{text.Text}";
    text.Hint = $"{text.Hint}";
}

it throws this exception: https://pastebin.com/EmkuL7hM

Layout:

   <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:fillViewport="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:paddingTop="50dp"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/backgroundColor">
       <LinearLayout
            android:layout_margin="10dp"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">
            <ImageView
                android:id="@+id/logo"
                android:layout_width="200dp"
                android:layout_height="100dp"
                android:src="@drawable/ic_logo_red"
                android:scaleType="fitCenter" />
        </LinearLayout>
       <LinearLayout
            android:layout_marginTop="10dp"
            android:layout_marginLeft="25dp"
            android:layout_marginRight="25dp"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">
            <TextView
                android:text="Email"
                local:MvxLang="Text Email"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/primaryColor"
                android:textStyle="bold"
                android:textSize="@dimen/text_medium" />
            <EditText
                android:layout_marginTop="5dp"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                local:MvxBind="Text LoginName"
                android:singleLine="true"
                android:inputType="textEmailAddress"
                android:background="@color/white"
                android:cursorVisible="true"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:textColorHint="@color/primaryTextColor"
                android:textColor="@color/primaryTextColor" /> 

            </LinearLayout>
            <LinearLayout
            android:layout_marginTop="10dp"
            android:layout_marginLeft="25dp"
            android:layout_marginRight="25dp"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">
            <TextView
                android:text="Password"
                local:MvxLang="Text Password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/primaryColor"
                android:textStyle="bold"
                android:textSize="@dimen/text_medium" />
            <EditText
                android:layout_marginTop="5dp"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                local:MvxBind="Text Password"
                android:singleLine="true"
                android:inputType="textPassword"
                android:background="@color/white"
                android:cursorVisible="true"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:textColorHint="@color/primaryTextColor"
                android:textColor="@color/primaryTextColor" />
        </LinearLayout>
        <LinearLayout
            android:layout_marginTop="20dp"
            android:layout_marginLeft="25dp"
            android:layout_marginRight="25dp"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">
            <Button
                android:gravity="center"
                android:id="@+id/loginButton"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="@dimen/text_large"
                local:MvxLang="Text Login"
                local:MvxBind="Click LoginCommand"
                android:padding="10dp"
                android:background="@drawable/button_round_primary"
                android:textColor="@color/white"
                android:text="Login"
                android:textStyle="bold" />
        </LinearLayout> 
    </LinearLayout>
</ScrollView>

ViewModel:

  public class LoginViewModel : MvxViewModel
    {
        private readonly IMvxNavigationService _navigationService;
        private readonly IInfoMessageReporter _infoMessageReporter;
        private readonly ISessionInfo _session;
        private readonly ILoginService _loginService;
        private readonly IDataService _dataService;

        public LoginViewModel()
        {
            _navigationService = Mvx.IoCProvider.Resolve<IMvxNavigationService>();
            _infoMessageReporter = Mvx.IoCProvider.Resolve<IInfoMessageReporter>();
            _session = Mvx.IoCProvider.Resolve<ISessionInfo>();
            _loginService = Mvx.IoCProvider.Resolve<ILoginService>();
            _dataService = Mvx.IoCProvider.Resolve<IDataService>();

            RememberLogin = true;
        }

        public IMvxLanguageBinder TextSource => new MvxLanguageBinder(Constants.LocalizationNamespace, GetType().Name);

        public override async Task Initialize()
        {
            await InitializePermissionsAsync();
        }

        private async Task InitializePermissionsAsync()
        {
            // some stuff...
        }

        private string _password;
        public string Password
        {
            get => _password;
            set
            {
                _password = value;
                RaisePropertyChanged(() => Password);
            }
        }

        private string _loginName;
        public string LoginName
        {
            get => _loginName;
            set
            {
                _loginName = value;
                RaisePropertyChanged(() => LoginName);
            }
        }

        private MvxAsyncCommand _loginCommand;
        public IMvxAsyncCommand LoginCommand
        {
            get
            {
                _loginCommand = _loginCommand ?? new MvxAsyncCommand(async () => await ExecuteLoginAsync());
                return _loginCommand;
            }
        }

        private async Task ExecuteLoginAsync()
        {
            // some stuff....
        }
    }

Solution

  • I believe the issue you are experiencing is a current bug in Xamarin's latest build (around Xamarin Android 9.4). This issue can be tracked here on GitHub.


    The suggested workaround

    In case any other users come across this issue when using Xamarin.Android 9.4, a possible workaround is to use a custom linker configuration to preserve the missing types. To do that, add a new linker.xml file to the project, set the Build Action to LinkDescription, and add the XML lines to preserve the missing types. For example, for the ITextWatcherInvoker error, add the following lines to the file:

    <linker>
     <assembly fullname="Mono.Android">
       <type fullname="Android.Text.ITextWatcherInvoker" preserve="all" />
     </assembly>
    </linker>