首页 > 解决方案 > 一段时间后,在后台(iOS和Android)上传数据以一种奇怪的方式失败

问题描述

我正在努力改进我们用于划船社区的应用程序。其中一部分是网站上的地图,其中包含来自 Boats 的最新位置。到目前为止一切正常,但我想添加一个连续的背景跟踪作为应用程序功能。

该应用程序可以运行一段时间,但由于超时而无法上传。这些并非来自 API 限制,在我看来,该应用程序似乎无法再访问网络了。

我依赖https://github.com/jamesmontemagno/GeolocatorPlugin获取所有位置信息。该插件还在Android 上使用https://github.com/jamesmontemagno/CurrentActivityPlugin/ 。

所以,这就是我从手机收到位置更新后要做的事情。

事件处理程序设置:

[...]
            TimeSpan span = new TimeSpan(0, 20, 0);  // Prod: 0, 30,  0
            double distance = 500;   // Prod: 2700

            bool includeHeading = false; //don't alert on heading changes 

            ListenerSettings listenerSettings = new ListenerSettings
            {
                AllowBackgroundUpdates = true,
                DeferralDistanceMeters = distance,      // adjustable in app 2-10 nautical Miles
                DeferLocationUpdates = true,
                DeferralTime = span,                    // adjustable in app 15-120 Minutes
                ListenForSignificantChanges = false,
                PauseLocationUpdatesAutomatically = false,
                ActivityType = ActivityType.OtherNavigation
            };

            var success = await CrossGeolocator.Current.StartListeningAsync(span,distance,includeHeading,listenerSettings);

            if (success)
            {
                CrossGeolocator.Current.PositionChanged += async (s, e) =>
                {

                    Console.WriteLine("\n\n -_-_-_-_-_ Position Event -_-_-_-_-_-_ \n\n");
                    Trackpoint trackpoint = new Trackpoint(e.Position);
                    Trackpoint point = await Tracking(trackpoint);
                };
            }
[...]

事件处理程序调用:(在应用程序开发路线图的下方会发生更多事情)

public async Task<Trackpoint> Tracking(Trackpoint trackpoint = null)
        {
            return await tracker.LogPoint(trackpoint);
        }

tracker.LogPoint(trackpoint)来自 Hevent Handler 的坐标被添加到列表中(应该是空的,但可能会保存以前的 Trackpoints,以防上传失败。)

public async Task<Trackpoint> LogPoint(Trackpoint location = null)
        {
            if (location == null)
            {
                location = await GetCoordinates();   // Call GPS if no Trackpoint is given when Tracking is done fully manual
            }

            if (location != null)
            {
                Console.WriteLine("Trackpoint Queue was: {0}", track.Count);
                track.Add(location);   // Add current location to end of the list (defined as private in the class)
                int trackpointQueue = track.Count;
                int uploadedTrackpoints = 0;

                Console.WriteLine("Trackpoint Queue now: {0}", trackpointQueue);

                foreach (var position in track)
                {
                    Console.WriteLine("Uploading Trackpoint: {0} | {1} | {2}", position.Timestamp, position.Latitude, position.Longitude);
                    if (App.api.UploadTrackPoint(track[track.Count - 1]))   // upload first trackpoint in List (ideally current) and remove it from List, repeat with more items in queue.
                    {
                        uploadedTrackpoints++;
                    }
                    else
                    {
                        Console.WriteLine("Error uploading Trackpoint trying again next time");
                        // Because uploading attempt failed, we don't want to try again now leave the loop until next call.
                        break;
                    }
                }
                track.RemoveRange(0, uploadedTrackpoints); // remove all uploaded Trackpoints from Queue
            }
            return location;
        }

上传是作为 multipart/formdata 到现有 API 的。在 4-10 个事件之后,所有进一步的上传都失败,因为发生网络超时而引发 Exeption。将应用程序带回前台,它几乎没有响应。

public bool UploadTrackPoint(Trackpoint location)
        {
            bool success = false;
            if (CanUseData())
            {
                string posturl = settings.BlogURL + "(THE API URL)" + "(THE API KEY)";
                string agent = "User-Agent: (MY APP NAME)/" + settings.Version + " (" + DeviceInfo.Platform + ", " + DeviceInfo.VersionString + ")";

                Console.WriteLine("Uploading: {0} ", Trackpoint.ConvertToString(location));
                try
                {
                    var response = MessageUpload.MultipartFormDataPost(false, posturl, agent, location.Pairs);

                    Console.WriteLine("HTTP response StatusCode: " + response.StatusCode + "\n Content: " + response.ResponseUri);

                    if (response.StatusCode == System.Net.HttpStatusCode.OK) success = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("FAILED!!! \n\n({0})\n\n", ex);

                }
            }
            return success;
        }

完全相同的行为发生在 iOS(物理 iPhone 6)和 iOS 模拟器以及 Android 模拟器中。但是,我阅读了很多关于 iOS 和最近的 Android API 的背景限制,但我怀疑这是这里的问题,因为它在两个平台上都是一致的。所以我假设我在这里做错了什么,在撞墙之前填充了一些缓冲。但是,该应用程序没有被任何操作系统终止,而-_-_-_-_-_ Position Event -_-_-_-_-_-_在上传开始失败并且积压工作增加后,我可以在控制台上看到一些。最终,在发生一些超时之后,甚至位置更新也会停止。

你会从哪里开始进一步的调试?

标签: c#xamarin

解决方案


以防万一有人偶然发现这一点。除了@SushiHangover 提到的缺少背景服务之外,更大的问题是 WebResponse 的处理不正确。

事实证明,撞到某种墙的直觉就在这里:在我的 Http 调用完成后,只读取标题并且从不处理响应对象,应用程序保持所有连接打开。在精确 10 之后(在 iOS 上),应用程序无法打开新连接,导致超时。


推荐阅读