android - MvvmCross 和 Android 通知

标签 android xamarin xamarin.forms xamarin.android mvvmcross

我正在创建使用 Xamarin.FormsMvvmCross 6.1.2 构建的应用程序,并且需要向 显示通知>用户。单击通知后,需要显示特定屏幕。目前我正在尝试在android上实现这个功能。我使用 Notification.Builder 来创建和显示通知,并且在执行此操作时需要提供要运行的 Intent 。

创建 Intent :

var request = MvxViewModelRequest<SomeViewModel>.GetDefaultRequest();
var translator = Mvx.Resolve<IMvxAndroidViewModelRequestTranslator>();
var intent = translator.GetIntentFor(request);

不幸的是,它崩溃并提示Type isn'therited from Java.Lang.Object。我卡住了,找不到任何示例或解释如何在单击通知时导航到特定屏幕/ View 模型。 MvvmCross 示例均不包含此类功能。

真的需要你的帮助!

此外,为了演示这个问题,我在 github 上创建了一个简单的项目: https://github.com/oleg-savoskin/mvvmcross-sample


更新 1(堆栈跟踪):

07-07 13:04:32.734 I/MonoDroid(15618): UNHANDLED EXCEPTION:
07-07 13:04:32.785 I/MonoDroid(15618): System.ArgumentException: type
07-07 13:04:32.785 I/MonoDroid(15618): Parameter name: Type is not derived from a java type.
07-07 13:04:32.785 I/MonoDroid(15618):   at Java.Lang.Class.FromType (System.Type type) [0x00012] in <263adecfa58f4c449f1ff56156d886fd>:0 
07-07 13:04:32.785 I/MonoDroid(15618):   at Android.Content.Intent..ctor (Android.Content.Context packageContext, System.Type type) [0x00000] in <263adecfa58f4c449f1ff56156d886fd>:0 
07-07 13:04:32.785 I/MonoDroid(15618):   at MvvmCross.Platforms.Android.Views.MvxAndroidViewsContainer.GetIntentFor (MvvmCross.ViewModels.MvxViewModelRequest request) [0x0003f] in <17df0d0bdae848b7a8a12b58d710f763>:0 
07-07 13:04:32.785 I/MonoDroid(15618):   at Sample.Droid.Services.NotificationService.GetContentIntent () [0x0000d] in D:\TEMP\Repositories\Sample\Sample.Android\Services\NotificationService.cs:31 
07-07 13:04:32.785 I/MonoDroid(15618):   at Sample.Droid.Services.NotificationService.ShowNotification () [0x00001] in D:\TEMP\Repositories\Sample\Sample.Android\Services\NotificationService.cs:15 
07-07 13:04:32.785 I/MonoDroid(15618):   at Sample.Core.ViewModels.HomeViewModel.ShowNotification () [0x00001] in D:\TEMP\Repositories\Sample\Sample.Core\ViewModels\HomeViewModel.cs:25 
07-07 13:04:32.786 I/MonoDroid(15618):   at MvvmCross.Commands.MvxCommand.Execute (System.Object parameter) [0x00009] in <17df0d0bdae848b7a8a12b58d710f763>:0 
07-07 13:04:32.786 I/MonoDroid(15618):   at Xamarin.Forms.Button.SendClicked () [0x00008] in D:\a\1\s\Xamarin.Forms.Core\Button.cs:132 
07-07 13:04:32.786 I/MonoDroid(15618):   at Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer+ButtonClickListener.OnClick (Android.Views.View v) [0x0000b] in D:\a\1\s\Xamarin.Forms.Platform.Android\AppCompat\ButtonRenderer.cs:291 
07-07 13:04:32.786 I/MonoDroid(15618):   at Android.Views.View+IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_v) [0x0000f] in <263adecfa58f4c449f1ff56156d886fd>:0 
07-07 13:04:32.786 I/MonoDroid(15618):   at (wrapper dynamic-method) System.Object.3ef246c1-103e-48ba-ba77-3d677f97466e(intptr,intptr,intptr)

更新2
我设法通过提供主要 Activity 作为目标类型来使其以某种方式工作。它会打开应用程序,但实际上并未导航到“第 2 页”。

    public class NotificationService : INotificationService
    {
        public void ShowNotification()
        {
            var notification = new NotificationCompat.Builder(Application.Context)
                .SetContentTitle("Sample app")
                .SetContentText("Click here to navigate to page 2")
                .SetSmallIcon(Resource.Drawable.ic_notification)
                .SetContentIntent(GetContentIntent())
                .SetShowWhen(false)
                .Build();

            var notificationManager = NotificationManagerCompat.From(Application.Context);
            notificationManager.Notify(1, notification);
        }

        private PendingIntent GetContentIntent()
        {
            var request = MvxViewModelRequest<Page2ViewModel>.GetDefaultRequest();

            var converter = Mvx.Resolve<IMvxNavigationSerializer>();
            var requestText = converter.Serializer.SerializeObject(request);

            var intent = new Intent(Application.Context, typeof(MainActivity)) // <-- It's here;
            intent.PutExtra("MvxLaunchData", requestText);

            return PendingIntent.GetActivity(Application.Context, 0, intent, 0);
        }
    }

但有时它仍然会崩溃,并出现错误 System.NotSupportedException:无法从 native 句柄 0x7fc0da6d44 激活 Xamarin.Forms.Platform.Android.PageRenderer 类型的实例

知道我在这里做错了什么吗?

最佳答案

您的更新 2 走在正确的轨道上。第一个问题是,MvvmCross 似乎在 Android 内部使用 Intents,但其中一些无法传递给 Android 方法,因为引用的类型不继承自Java.Lang.Object。

此代码正在运行,位于 https://github.com/curtisshipley/mvvmcross-sample

它处理主 Activity 运行时和不运行时的情况。根据情况,如果 MainActivity 未运行,则 Intent 会有不同的入口点:OnCreateOnNewIntent 如果是的话。在示例代码中,这些仅调用 NavigateToRequestIfPresent

此外,我对 NavigationService 进行了一些小调整,以便它可以与派生自 IMvxViewModel 的任何 ViewModel 配合使用。

public void ShowNotification<VM>() where VM : IMvxViewModel
{
    var notification = 
        new NotificationCompat.Builder(Application.Context, SampleApplication.NOTIFICATION_CHANNEL)
        .SetContentTitle("Sample app")
        .SetContentText("Click here to navigate to page 2")
        .SetSmallIcon(Resource.Drawable.ic_notification)
        .SetContentIntent(GetContentIntent<VM>())
        .SetShowWhen(false)
        .Build();

    var notificationManager = NotificationManagerCompat.From(Application.Context);
    notificationManager.Notify(1, notification);
}

private PendingIntent GetContentIntent<VM>() where VM : IMvxViewModel
{
    var request = MvxViewModelRequest<VM>.GetDefaultRequest();

    var converter = Mvx.Resolve<IMvxNavigationSerializer>();
    var requestText = converter.Serializer.SerializeObject(request);

    var intent = new Intent(Application.Context, typeof(MainActivity)); 

    // We only want one activity started
    intent.AddFlags(ActivityFlags.SingleTop);

    intent.PutExtra("MvxLaunchData", requestText);

    // Create Pending intent, with OneShot. We're not going to want to update this.
    return PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.OneShot);
}

为了响应,我们需要允许 MainActivity 了解 Intent 。此方法检查 View 模型的序列化请求的 Intent。如果存在的话, 我们反序列化然后导航。

protected void NavigateToRequestIfPresent(Intent intent)
{
    // If MvxLaunchData is present, we then know we should navigate to that intent
    var requestText = intent.GetStringExtra("MvxLaunchData");

    if (requestText == null)
        return;

    var viewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();

    var converter = Mvx.Resolve<IMvxNavigationSerializer>();
    var request = converter.Serializer.DeserializeObject<MvxViewModelRequest>(requestText);

    viewDispatcher.ShowViewModel(request);
}

最后一点,从 Android Oreo 开始,这种创建通知的特殊方式需要一个NotificationChannel。

关于android - MvvmCross 和 Android 通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51216823/

相关文章:

java - Android Studio - 应用程序崩溃

Android OpenGL ES 不光栅化 - 矩阵乘法切换

java - 尝试更改 android 上的 Firebase 数据库中的值时循环

android - 如何复制并粘贴到 Xamarin Android Player?

Xamarin Forms Mediaplugin 文件提供程序

android,NDK, 将日志写入文件

c# - 将 azure 存储客户端库与 xamarin 结合使用

android - Xamarin Player 启动报错

xamarin - 如何使我的应用程序与智能电视兼容?

android - 项目不兼容 monoandroid81(MonoAndroid,Version=v8.1)