MessagingCenter多次触发Xamarin的问题

qgzx9mmu  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(173)

I have looked all over for a solution to an issue. I have noticed that in my android app, every time I fire an event from <button Clicked="GPSToggle_Clicked"> , for some reason it increments the number of times my methods get called. So after I compile and load this on my phone, I hit my "GPSToggle_Clicked" button, and then to stop hit that button again. On the first "stop", I'll get a single instance of the below output:

---------------------------------------------------------------Attempting string parsing
---------------------------------------------------------------Sending string to SubmitGeneratedGPX
---------------------------------------------------------------path: /storage/emulated/0/Download/GPX/2022-10-27-02-44-06.gpx
---------------------------------------------------------------GPX File creation success
---------------------------------------------------------------:RawBufferToJsonString: [{"Timestamp":"2022-10-27T18:43:52.849+00:00","Latitude":41.5263818,"Longitude":-81.6507923,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7990270853042603,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:53.696+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:54.526+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:55.374+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:56.21+00:00","Latitude":41.5263811,"Longitude":-81.650792,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7160584926605225,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2}]

Every subsequent time I hit start/stop on the app, I get the real-time data in the output multiplied by the number of times I've started/stopped since the last compiling.
the main app page button event thats fired:

private async void GPSToggle_Clicked(object sender, EventArgs e)
    {
        var LocationPermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.LocationAlways>();
        var FileReadPermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.StorageRead>();
        var FileWritePermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.StorageWrite>();
        if(LocationPermissionStatus == Xamarin.Essentials.PermissionStatus.Denied)
        {
            // TODO
            return;
        }
        
        // run if device is android
        if(Device.RuntimePlatform == Device.Android)
        {
            if (!CrossGeolocator.Current.IsGeolocationAvailable || !CrossGeolocator.Current.IsGeolocationEnabled)
            {
                // gps is not enabled, throw alert
                Console.WriteLine("---------------------------------------------------------------GPS is DISABLED");
                await DisplayAlert("Error", "GPS is not enabled. You must enable GPS to use this feature", "Ok");
            }
            else
            {
                // set our IsTracking = true flag
                if (!IsTracking)
                {
                    // start background listening for GPS
                    await StartListening();
                    Console.WriteLine("---------------------------------------------------------------Listening: " + CrossGeolocator.Current.IsListening);
                    StartService();
                    Console.WriteLine("---------------------------------------------------------------Service initiated");
                    IsTracking = true;
                    Console.WriteLine("---------------------------------------------------------------Tracking initiated");
                    GPSToggle.Text = "Stop Tracking";
                }
                else
                {
                    //
                    // verify that the submittal wasn't done in error, before stopping services and submitting data
                    bool DoneInError = await DisplayAlert("Finish?", "Are you sure you want to stop services and submit?", "No", "Yes");
                    if (!DoneInError)
                    {
                        await StopListening();
                        Console.WriteLine("---------------------------------------------------------------listening:" + CrossGeolocator.Current.IsListening);
                        IsTracking = false;
                        Console.WriteLine("---------------------------------------------------------------Tracking ceased");
                        // stop the gps service
                        StopService();
                        Console.WriteLine("---------------------------------------------------------------Service ceased");
                        // stop the background listening for gps
                        Console.WriteLine("---------------------------------------------------------------Attempt GPX parse from buffer obj");

                        GPSToggle.Text = "Start Tracking";
                    }
                }
            }
        }
    }

Specifically the line:

StartService();

Fires this method off within the same class, specifically the MessagingCenter.Send<>, which initiates my foreground service to handle logging the gps data into a buffer:

private void StartService()
    {            
        var startServiceMessage = new StartServiceMessage();
        MessagingCenter.Send(startServiceMessage, "ServiceStarted");
        Preferences.Set("LocationServiceRunning", true);
        StatusLabel.Text = "Location service has been started";
        Console.WriteLine("---------------------------------------------------------------location service has been started. preferences saved");
    }

and

StopService();

Fires this method off to stop the services and retrieve the gps buffer data from the foreground to the main thread:

private void StopService()
    {
        var stopServiceMessage = new StopServiceMessage();
        MessagingCenter.Unsubscribe<App, List<Location>>(this, "GPXBufferData");
        MessagingCenter.Subscribe<App, List<Location>>(this, "GPXBufferData", (sender, args) =>
        {
            RawGPXData = args;
            Generate_CreateGPX_File(RawGPXData);
            RawBufferToJsonString = GPXParse.GenerateJSON_GPXPoints(RawGPXData);
            Console.WriteLine("---------------------------------------------------------------:RawBufferToJsonString: " + RawBufferToJsonString);
            PromptForSubmission_GPXPoints_API();
        });
        Console.WriteLine("--------------------------------------------------------------------------");
        MessagingCenter.Send(stopServiceMessage, "ServiceStopped");
        Preferences.Set("LocationServiceRunning", false);
        Console.WriteLine("---------------------------------------------------------------Location service stopped. preferences saved");
    }

In the above snippet, this line is subscribed to in the GPSLocationService.cs file:

MessagingCenter.Send(stopServiceMessage, "ServiceStopped");

This is a portion of my GPSLocationService.cs file that is relevant to this:

public async Task Run(CancellationToken token)
    {
        int ObjCount = 0;
        await Task.Run(async () => {
            // if the task was stopped
            // check the buffer for data, if data, send to GPXGenerator
            MessagingCenter.Subscribe<StopServiceMessage>(this, "ServiceStopped",
            message =>
            {
                if (GPSBufferObj != null)
                {
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        MessagingCenter.Unsubscribe<App, List<Location>>((App)Xamarin.Forms.Application.Current, "GPXBufferData");
                        MessagingCenter.Send<App, List<Location>>((App)Xamarin.Forms.Application.Current, "GPXBufferData", GPSBufferObj);

                    });
                }
            });

            return;
        }, token);
    }

I believe I have tracked down where the issue is starting. In my StopService() method, I have the following line (just to keep track of where Im at in the buffer) and it is only sent to output once.

Console.WriteLine("--------------------------------------------------------------------------");

BUT if I place that same line within the pasted portion of my GPSLocationService.cs file, I will get the incremented output. I'm leaning towards the nested task being the issue, I wrote this based losely off of this example repro: https://github.com/jfversluis/XFBackgroundLocationSample

7lrncoxx

7lrncoxx1#

您的代码中没有MessagingCenter.Unsubscribe<StopServiceMessage>**。StopServiceMessage是您要累积订阅的内容。
您需要确保Unsubscribe正在取消订阅之前订阅的示例。听起来好像有多个GPSLocationService示例。[在这种情况下,this不再引用原始示例。取消订阅不会执行任何操作,除非您拥有最初订阅的this。]
如果是这样的话,创建一个GPSLocationService ONCE的示例,并将其存储在一个静态变量中。重复使用它。启动/停止它,但不要丢弃它。
或者,如果您只需要每次订阅一条消息,请在收到每条消息后立即取消订阅:

MessagingCenter.Subscribe<StopServiceMessage>(this, "ServiceStopped",
  message =>
  {
    MessagingCenter.Unsubscribe<StopServiceMessage>(this, "ServiceStopped");
    ... your code ...
  });

在任何有订阅的地方都使用相同的模式(除非像Jason建议的那样,在应用程序启动时只订阅一次。)

相关问题