Mystery nullReferenceException возникает после обновления с Xamarin. Формы с 4.1 до 4.2+ - PullRequest
1 голос
/ 13 января 2020

После обновления моего приложения с Xamarin.Forms 4.1.0.709244 до 4.2.0.709249 (или любой более новой версии пакета) код, который ранее работал без сбоев, теперь больше не работает и падает, но только при одном конкретном c обстоятельстве.

Мое приложение получает уведомления pu sh через пакет OneSignal , а ожидаемое поведение:

  1. Приходит и открывается уведомление
  2. Обработчик открытого уведомления сохраняет полезную нагрузку в App параметрах класса и устанавливает Application.Current.MainPage = new MainPage();
  3. Logi c в инициализаторе MainPage анализирует полезную нагрузку, чтобы определить, на какую страницу должен перейти пользователь и создает объект Page для этой новой страницы.
  4. Detail Для страницы задана новая страница

Под 4.1 , это сработало, как и ожидалось. Нажав на уведомление, пользователь попадет на соответствующую страницу в приложении под всеми сценариями ios. После обновления до 4.2 + этот сценарий завершается ошибкой, если приложение в данный момент не запущено, но работает должным образом, если приложение запущено и находится либо на переднем плане, либо в фоновом режиме.

При сбое, вместо загрузки приложения, а затем перехода пользователя на правильную страницу, приложение загружается, но затем просто сидит на главной странице по умолчанию (как если бы Detail не было установлено с использованием информации из полезной нагрузки уведомления). Кроме того, в этот момент, если вы нажмете на значок гамбургера, на короткое время отобразится меню навигации, и приложение сразу же завершит работу с исключением нулевой ссылки, показанным ниже:

System.NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта в Xamarin.Forms.Platform. Android .AppCompat.Platform.Xamarin.Forms.Platform. Android .IPlatformLayout.OnLayout (System.Boolean изменено, System.Int32 l, System.Int32 t, System. Int32 r, System.Int32 b) [0x0002b] в <596751900f1f46919eb25349c2e7053a>: 0 в Xamarin.Forms.Platform. Android .PlatformRenderer.OnLayout (System.Boolean изменено, System.Int32 l, System.Int32 l, System.Int32 t r, System.Int32 b) [0x00025] в <596751900f1f46919eb25349c2e7053a>: 0 в Android .Views.ViewGroup.n_OnLayout_ZIIII (System.IntPtr jnienv, System.IntPtr System__this, System. t, System.Int32 r, System.Int32 b) [0x00009] in <21b22bf2aca24508938d2117f4c11761>: 0 at (метод оболочки) c -метод) Android .Runtime.Dyna micMethodNameCounter.28 (intptr, intptr, bool, int, int, int, int)

Поскольку этот сценарий происходит только тогда, когда приложение закрывается и запускается с помощью действия уведомления, я не могу использовать Visual Studio отладчик, чтобы точно определить, где происходит исключение. Я использовал Microsoft AppCenter , чтобы добавить ряд событий, которые будут отслеживать ход выполнения различными методами, а затем сообщать, где в потоке логики c произошла ошибка sh, но все ожидаемые шаги выполняются до конца. , Вызывается шаг для установки страницы Detail в качестве новой страницы, и обработчик isPresentedChanged, который вызывается при нажатии значка гамбургера, также выполняется до конца.

Я ознакомился с выпуском примечания для 4.2 здесь и хотя есть несколько исправлений, связанных с макетом страницы, которые могут быть связаны с cra sh, я чувствую, что cra sh больше признак того, что изменение страницы «Сведения» происходит неправильно, чем проблема, которую мне нужно решить сразу. Я обнаружил несколько схожих ошибок, сообщенных команде Xamarin, но все они закрыты как исправленные и не являются точно такой же проблемой. См. здесь , здесь , здесь , здесь и здесь для тех.

NotificationServices.cs (расширение службы для OneSignal ; код теперь не работает независимо от того, какой userNotificationType передан):

public class NotificationServices
{
    public static void HandleNotificationOpened(OSNotificationOpenedResult result)
    {
        string notificationActionId = "HandleMessage";

        OSNotificationPayload payload = result.notification.payload;
        string message = payload.body;
        App.NotificationActionId = notificationActionId;
        App.NotificationData = payload.additionalData;
        Application.Current.MainPage = new MainPage();
    }

    public static Page GetPageFromNotificationData()
    {
        Page ReturnPage;
        ApiServices _apiServices = new ApiServices();  //service to make REST calls to backend system
        user_notification_type userNotificationType = user_notification_type.None;
        int fromUserId = 0;
        int assocId = 0;
        int msgId = 0;
        if (App.NotificationData != null)
        {
            if (App.NotificationData.ContainsKey("assocId"))
            {
                Int32.TryParse(Convert.ToString(App.NotificationData["assocId"]), out assocId);
            }
            if (App.NotificationData.ContainsKey("fromUserId"))
            {
                Int32.TryParse(Convert.ToString(App.NotificationData["fromUserId"]), out fromUserId);
            }
            if (App.NotificationData.ContainsKey("msgId"))
            {
                Int32.TryParse(Convert.ToString(App.NotificationData["msgId"]), out msgId);
            }
            if (App.NotificationData.ContainsKey("userNotificationType"))
            {
                int unInt = 0;
                Int32.TryParse(Convert.ToString(App.NotificationData["userNotificationType"]), out unInt);
                userNotificationType = (user_notification_type)unInt;
            }
        }
        switch (userNotificationType)
        {
            case user_notification_type.ChatMessage:
                TeamBasic tm = new TeamBasic();
                tm.OwnerID = fromUserId;
                tm.OwnerName = _apiServices.GetUserName(fromUserId).Result;
                ReturnPage = new ChatPage(tm);
                break;
            case user_notification_type.None:
                ReturnPage = default(Page);
                break;
            default:
                UserNotification unItem = new UserNotification();
                var unList = _apiServices.GetUserNotifications(assocId, msgId+1, 1).Result;
                unItem = unList[0];
                UserNotificationDetailViewModel undVm = new UserNotificationDetailViewModel(unItem);
                ReturnPage = new UserNotificationDetailPage(undVm);
                break;
        }

        return ReturnPage;
    }
}

Mainpage.xaml. cs :

public partial class MainPage : MasterDetailPage
{
    private IHubServices _hubServices;
    Dictionary<int, NavigationPage> MenuPages = new Dictionary<int, NavigationPage>();
    public MainPage()
    {
        InitializeComponent();

        _hubServices = DependencyService.Get<IHubServices>(); //signalR
        _hubServices.Connect();
        _hubServices.ClearPageCache += ClearPageCache;

        MasterBehavior = MasterBehavior.Popover;
        NavigationPage navPage = (NavigationPage)Detail;

        ConnectionState cs = _hubServices.GetConnectionState().Result;
        if (cs == ConnectionState.Connected)
        {
            var pg = NotificationServices.GetPageFromNotificationData();  //call to get page as specified per notification

            Detail = new NavigationPage(pg); //this is where the Detail page should be getting updated but is acting like it isn't when the app is started by the act of opening the notification
            MenuPages.Add((int)MenuItemType.LogOut, (NavigationPage)Detail);
        }
        else
        {
            App.CheckForNotificationRedirect = true;
            MenuPages.Add((int)MenuItemType.About, (NavigationPage)Detail);
        }

        IsPresentedChanged += (sender, args) =>
        {
            try {
                //anything
            }
            catch (Exception ex) 
            {
                //anything
            }
            //it is after this has completed executing that the app is crashing.  No exception ever occurs in the try/catch
        };  
    }
}

Полный дамп, предоставленный App Center :

Стек исключений Xamarin: System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта в Xamarin.Forms.Platform. Android .AppCompat.Platform.Xamarin.Forms.Platform. Android .IPlatformLayout.OnLayout ( System.Boolean изменено, System.Int32 l, System.Int32 t, System.Int32 r, System.Int32 b) [0x0002b] в <596751900f1f46919eb25349c2e7053a>: 0 в Xamarin.Forms.Platform. Android .PlatformRenoutrenO .Boolean изменено, System.Int32 l, System.Int32 t, System.Int32 r, System.Int32 b) [0x00025] в <596751900f1f46919eb25349c2e7053a>: 0 в Android .Views.ViewGroup.n_OnLayout_ZIIII (System.Intv .IntPtr native__this, System.Boolean изменено, System.Int32 l, System.Int32 t, System.Int32 r, System.Int32 b) [0x00009] в <21b22bf2aca24508938d2117f4c11761>: 0 в (динамическая оболочка c -2 * *) * .Runtime.DynamicMethodNameCounter.28 (intptr, intptr, bool, int, int, int, int)

Thread 2:
0   dalvik.system.VMStack.getThreadStackTrace(VMStack.java:-2)
1   java.lang.Thread.getStackTrace(Thread.java:1538)
2   java.lang.Thread.getAllStackTraces(Thread.java:1588)
3   com.microsoft.appcenter.crashes.Crashes.saveUncaughtException(Crashes.java:1093)
4   com.microsoft.appcenter.crashes.WrapperSdkExceptionManager.saveWrapperException(WrapperSdkExceptionManager.java:58)
5   crc643f46942d9dd1fff9.PlatformRenderer.n_onLayout(PlatformRenderer.java:-2)
6   crc643f46942d9dd1fff9.PlatformRenderer.onLayout(PlatformRenderer.java:55)
7   android.view.View.layout(View.java:20740)
8   android.view.ViewGroup.layout(ViewGroup.java:6268)
9   android.widget.RelativeLayout.onLayout(RelativeLayout.java:1084)
10  android.view.View.layout(View.java:20740)
11  android.view.ViewGroup.layout(ViewGroup.java:6268)
12  android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
13  android.widget.FrameLayout.onLayout(FrameLayout.java:261)
14  android.view.View.layout(View.java:20740)
15  android.view.ViewGroup.layout(ViewGroup.java:6268)
16  android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
17  android.widget.FrameLayout.onLayout(FrameLayout.java:261)
18  android.view.View.layout(View.java:20740)
19  android.view.ViewGroup.layout(ViewGroup.java:6268)
20  android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
21  android.widget.FrameLayout.onLayout(FrameLayout.java:261)
22  android.view.View.layout(View.java:20740)
23  android.view.ViewGroup.layout(ViewGroup.java:6268)
24  android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
25  android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
26  android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
27  android.view.View.layout(View.java:20740)
28  android.view.ViewGroup.layout(ViewGroup.java:6268)
29  android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
30  android.widget.FrameLayout.onLayout(FrameLayout.java:261)
31  com.android.internal.policy.DecorView.onLayout(DecorView.java:794)
32  android.view.View.layout(View.java:20740)
33  android.view.ViewGroup.layout(ViewGroup.java:6268)
34  android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2970)
35  android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2465)
36  android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1571)
37  android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7616)
38  android.view.Choreographer$CallbackRecord.run(Choreographer.java:1034)
39  android.view.Choreographer.doCallbacks(Choreographer.java:845)
40  android.view.Choreographer.doFrame(Choreographer.java:780)
41  android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1020)
42  android.os.Handler.handleCallback(Handler.java:873)
43  android.os.Handler.dispatchMessage(Handler.java:99)
44  android.os.Looper.loop(Looper.java:205)
45  android.app.ActivityThread.main(ActivityThread.java:6991)
46  java.lang.reflect.Method.invoke(Method.java:-2)
47  com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
48  com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)

Thread 41398:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:178)
2   java.lang.Daemons$Daemon.run(Daemons.java:103)
3   java.lang.Thread.run(Thread.java:764)

Thread 41399:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Object.wait(Object.java:422)
2   java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:188)
3   java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:209)
4   java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:232)
5   java.lang.Daemons$Daemon.run(Daemons.java:103)
6   java.lang.Thread.run(Thread.java:764)

Thread 41400:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:297)
2   java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:277)
3   java.lang.Daemons$Daemon.run(Daemons.java:103)
4   java.lang.Thread.run(Thread.java:764)

Thread 41415:
0   java.lang.Object.wait(Object.java:-2)
1   com.android.okhttp.ConnectionPool$1.run(ConnectionPool.java:103)
2   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
3   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
4   java.lang.Thread.run(Thread.java:764)

Thread 41416:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41417:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41419:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41420:
0   java.lang.Object.wait(Object.java:-2)
1   com.android.okhttp.okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:323)
2   com.android.okhttp.okio.AsyncTimeout.access$000(AsyncTimeout.java:40)
3   com.android.okhttp.okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:286)

Thread 41421:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41424:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41425:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41431:
0   android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1   android.os.MessageQueue.next(MessageQueue.java:326)
2   android.os.Looper.loop(Looper.java:170)
3   android.os.HandlerThread.run(HandlerThread.java:65)

Thread 41469:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Thread.parkFor$(Thread.java:2137)
2   sun.misc.Unsafe.park(Unsafe.java:358)
3   java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)
4   java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2101)
5   java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
6   java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)
7   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
8   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
9   com.google.android.gms.common.util.concurrent.zza.run
10  java.lang.Thread.run(Thread.java:764)

Thread 41470:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Thread.parkFor$(Thread.java:2137)
2   sun.misc.Unsafe.park(Unsafe.java:358)
3   java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
4   java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2059)
5   java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1120)
6   java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:849)
7   java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1092)
8   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
9   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
10  com.google.android.gms.common.util.concurrent.zza.run
11  java.lang.Thread.run(Thread.java:764)

Thread 41478:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Thread.parkFor$(Thread.java:2137)
2   sun.misc.Unsafe.park(Unsafe.java:358)
3   java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)
4   java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2101)
5   java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
6   java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)
7   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
8   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
9   java.lang.Thread.run(Thread.java:764)

Thread 41483:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Thread.parkFor$(Thread.java:2137)
2   sun.misc.Unsafe.park(Unsafe.java:358)
3   java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)
4   java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2101)
5   java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
6   java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)
7   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
8   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
9   java.lang.Thread.run(Thread.java:764)

Thread 41495:
0   java.lang.Object.wait(Object.java:-2)
1   java.lang.Thread.parkFor$(Thread.java:2137)
2   sun.misc.Unsafe.park(Unsafe.java:358)
3   java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)
4   java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2101)
5   java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
6   java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)
7   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
8   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
9   java.lang.Thread.run(Thread.java:764)

1 Ответ

1 голос
/ 06 февраля 2020

После долгих усилий по отслеживанию кода запуска было определено, что следующую строку в классе обслуживания необходимо заключить в вызов, чтобы убедиться, что он был вызван в главном потоке. Это не требовалось до Xamarin.Forms 4.2.

await Device.InvokeOnMainThreadAsync(() => {
    Application.Current.MainPage = new MainPage();
});
...