IGeolocator's PositionChanged firing twice? - c#

Context
I'm developing a traffic management app using C# (Xamarin Forms) which requires a constant feed of the user's location.
Plugin
I'm using the Geolocator plugin by James Montemagno and the PositionChanged event on the IGeolocator interface seems to be triggering twice when a position change occurs.
Device
I'm currently debugging on an Android Emulator on Visual Studio Enterprise v15.5.3
Steps to reproduce the behaviour
1) After instantiating the locator object:
IGeolocator locator = CrossGeolocator.Current
2) Some code for when the locator's PositionChanged is triggered:
locator.PositionChanged += (sender,e) => {
// Testing its frequency
System.Diagnostics.Debug.WriteLine("Position Changed Triggered.");
}
3) Start listening in an async Task function
locator.DesiredAccuracy = 100;
if(!locator.isListening)
await locator.StartListeningAsync(TimeSpan.FromMilliseconds(500), 1, true);
4) Send coordinates via the emulator
Expected Results
The output window should display one message saying "Position Changed Triggered".
Actual Results
The output window has two identical messages printed, saying: "Position Changed Triggered".
Why is this happening? and how can I make it so that the event is ONLY triggered/handled ONCE for every time the position is actually changed.
What I've tried so far
Googled the issue, not many identical situations found.
Saw an explanation here which makes me believe it's the emulator has something to do with it, although I found the solution a bit ambiguous and am not sure what they're referring to with "Live/Pin Mode"
Created a separate function and assigned the event to it, then removed it after calling my code. This does cause it to execute once, but it never executes again unless I reassign in. And if I do, sure enough the code will run for the second time, resulting in the same initial problem.
Tried setting a boolean to check if it has already run once, but realised not long after how that's illogical.
Tried to set a DateTime object to make sure no more than 1 event occurs in a given time frame; this was also no good.
Help would be appreciated. Thanks.

Please note that the location service might deliver a location event more than one time (more here).
Even if the location service is not delivering the location event more than one time, usage and/or implementation of the API (Geolocator plugin) might cause reception of the location event more than one time from the API.
In the app you might check the location event properties (accuracy, location timestamp, order of event received, etc.). Use the "best" location event with "best" meaning preferred accuracy, most recent timestamp, or the first received location event if timestamp and accuracy are equal.

Related

INotifyPropertyChanged Resubscribe not working, only the first time subscription working

I developing a Xamarin application, and I communicating an external custom device. My problem is very strange, firstly the application starting, and connecting automatically to device, so everything is fine. When i suddenly remove the battery from the external device, the bluetooth connection is broken, and it's working fine to, but when I turn on the external device again, my Xamarin application connecting to it very well well, but the subscriptions not working anymore.
I debugged it, but not calling anymore. I think the unsubscribe/subscribe process is wrong.
...
if (ble.GetConnectionStatus())
{
Device.BeginInvokeOnMainThread(() =>
{
...
ble.Adapter.DeviceConnectionLost -= Adapter_DeviceConnectionLost;
ble.Adapter.DeviceConnectionLost += Adapter_DeviceConnectionLost;
ble.PropertyChanged -= Ble_PropertyChanged;
ble.PropertyChanged += Ble_PropertyChanged;
data.PropertyChanged -= data_PropertyChanged;
data.PropertyChanged += data_PropertyChanged;
...
});
...
So it's so strange, because first time this working, when starting the app, but when I call it after reconnect that same subscription not working. So if its wrong, then why working this at very first time?
I have no error, just not fire the functions again after resubscribe.
So as you see, I need to "refresh" the subscription. Is there another way to solve this problem?
If that "button to recreate everything" works, then I see two alternatives.
Option 1:
Have such a button, so that user can manually "fix" the situation.
PRO: Gives the user a solution that is guaranteed to work.
CON: Requires user intervention.
Option 2:
Have a periodic timer, that decides whether/when to forcibly "fix" the situation.
PRO: Automatically recovers.
CON: Risks losing data, if forces a recovery at the same time data is arriving.
In pseudo-code, option 2 might be something like this:
// pseudo-code
static Timer timer = ..start a timer that has an event every 10 seconds.
OnTimerElapsed:
if (!eventSeenRecently)
ForceReset();
eventSeenRecently = false;
..whereever you receive data..
if (..has data..)
eventSeenRecently = true;
The concept is that you keep track of whether data continues to be received. If the device stops sending you information (but you believe it should be), then you "ForceReset" - whatever is needed to get everything going again.
DeviceConnectionLost should also set some flag, that you use to ForceReset when the device "comes back".
// pseudo-code
DeviceConnectionLost:
resetNeeded = true;
OnTimerElapsed:
if (resetNeeded && ..test that device is available again..) {
ForceReset();
resetNeeded = false;
}
Perhaps this custom device has some option or info that can help.
For example, there might be a way to query some id or other info, so you can discover that the device is now "different", in a way that requires the reset. Then the timer does that query, and uses that info to decide to reset.

TransactionTooLargeException from Samsung's SmartClip service crashing my app - can it be intercepted?

Android Samsung phones have a SmartClip service that is invoked when a screenshot is taken. It launches an interface to immediately allow the screenshot to be edited.
My app will often crash when this action is performed, specifically when a large number of objects are drawn on the screen. This is a Xamarin.Forms app.
When the crash occurs, two threads are reported as responsible, with the following stack traces:
android.os.BinderProxy.transactNative BinderProxy.java
android.os.BinderProxy.transact BinderProxy.java:605
com.samsung.android.content.smartclip.ISpenGestureService$Stub$Proxy.sendSmartClipRemoteRequestResult ISpenGestureService.java:910
com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:77
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130
com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:81
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130
So... what do I do? This is a crash originating in third party code that I'm not including myself. Is there a hook somewhere that I can prevent this action from executing, or to handle the exception without crashing my app?
The only other solution would be to reduce the number of objects displayed so it comes under the 1 Mb limit, but I'd like to avoid that.
EDIT to add: Unfortunately, it looks like UnhandledException handling is not going to suffice, it was only meant for logging information about the crash.
Thanks to #ToolmakerSteve I have a workaround.
I used the information in the links to detect this exception and restart the activity:
# in MainApplication.cs
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if ((e.ExceptionObject as RuntimeException)?.InnerException is TransactionTooLargeException)
{
Intent intent = new Intent(ApplicationContext, typeof(MainActivity));
intent.AddFlags(ActivityFlags.NewTask);
StartActivity(intent);
}
}
}
Trying to do any state-saving action in this method fails. You have to rely on state that's saved prior to the crash. Luckily I already had such a mechanism.
So I just needed to detect a crash on startup (I used AppCenter's Crashes.HasCrashedInLastSessionAsync() and run my state-restoring method. Though for some reason I could only run this check after populating MainPage. Doing it before risked a blank screen.
In addition to this, I implemented limits on the number of objects drawn on the screen, so that the crash happens less frequently.
This isn't the best answer because it would be better to stop the third party code from crashing apps, but I hope it helps someone else.

UnregisterKeys() method not executing in apache geode native client

After successfully subscribing to the region and setting up CacheListener and finishing using it, the UnregisterKeys() method in
Region.GetSubscriptionService().UnregisterKeys(new List<string>() { key }) seems not to be working as per screenshots.
After below code execution, the events still fire in AfterUpdate(EntryEvent<TKey, TVal> ev).
How do I unsubscribe from the region correctly?
I am using Apache Geode Native 1.10.0
running it on .NET WPF Framework 4.6.0
Image 1 - Getting interested Keys:
Image 2 - Executing UnregisterKeys and checking for Interested keys again.
Creating CacheFactory:
cacheFactory.Set("log-file", _serviceName + "Geode.log")
.Set("log-level", "info")
.Set("statistic-sampling-enabled", "false")
.Set("name", _serviceName)
.SetPdxReadSerialized(true)
.Create();
Creating Pool:
_cache.GetPoolManager()
.CreateFactory()
.SetSubscriptionEnabled(true)
.AddLocator(_host, _port)
.SetFreeConnectionTimeout(new TimeSpan(5000))
.Create();
Still working on a repro for this, but can say for sure this doesn't appear to be an issue with C++ talking to Geode Native from the latest develop branch. The following test code passes:
auto cache = createTestCache();
auto poolFactory =
cache.getPoolManager().createFactory().setSubscriptionEnabled(true);
cluster.applyLocators(poolFactory);
poolFactory.create("default");
auto region = setupCachingProxyRegion(cache);
std::vector<std::shared_ptr<CacheableKey> > keys;
keys.push_back(std::make_shared<CacheableInt32>(123456));
region->registerKeys(keys, false, true);
auto attrMutator = region->getAttributesMutator();
auto listener = std::make_shared<SimpleCacheListioner>();
attrMutator->setCacheListener(listener);
region->put(123456, "foo");
region->put(123456, "bar");
region->put(123456, "baz");
region->put(123456, "qux");
region->unregisterKeys(keys);
auto stillInterested = region->getInterestList();
EXPECT_EQ(stillInterested.size(), 0);
EXPECT_EQ(listener->getCreateCount(), 1);
EXPECT_EQ(listener->getUpdateCount(), 3);
EXPECT_EQ(listener->getInvalidateCount(), 0);
EXPECT_EQ(listener->getDestroyCount(), 0);
cache.close();
In theory, the C#/.net Geode Native client is just wrapping the C++ code with minimal changes, so the language shouldn't be an issue here, but of course I won't know 'til I try. Likewise, I don't recall any changes being made in this part of the code since the 1.10.0 drop, but again I won't know til I try, so rolling back to that commit and re-running the test is also on my to do list. When/if I learn any more, I'll provide an update here.
I think there is an issue with the test itself in this case.
The issue is with the assumption that a CacheListener is part of the subscription, but really it is just associated with the region and any event either local or remote can trigger the CacheListener. To determine the event source a user must inspect the EntryEvent for origin via the RemoteOrigin method as part of the Cachelistener event processing. The use of register interest in a key is a server side event and so unregistering interest in a key is also a server side action which should stop the push of events from the server to the client but a CacheListener will still be triggered for the local event. If you want the listener to no longer trigger then it must be set to null via the region AttributesMutator.

What triggers rebuild of webpack-bundle in HMR with SpaServices?

I'm using ASP.Net Core with Typescript/React/SpaServices/Webpack/HMR.
When changing a tsx file HMR replaces the code in the browser.
My question in what function/program is watching the files for changes and then triggers the rebuild? Is webpack running in the background using node? If so, can I see that process running? Logs etc?
Is webpack running in the background using node?
Yes, absolutely. There's a lot going on here, but ultimately both webpack and the webpack-dev-middleware are handling this.
It starts with the call to UseWebpackDevMiddleware. e.g.:
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
As I've already said, there's a lot going on behind the scenes here, so I'll just give an overview of the main parts at play. Here's an important line of code from UseWebpackDevMiddleware (source):
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(
nodeScript.FileName,
"createWebpackDevServer",
JsonConvert.SerializeObject(devServerOptions)).Result;
The InvokeExortAsync function is where the communication between ASP.NET Core and NodeJs occurs. The nodeServices variable is an instance of HttpNodeInstance, which is a child of OutOfProcessNodeInstance. The OutOfProcessNodeInstance class spawns a NodeJs server when it's constructed, like so (source):
_nodeProcess = LaunchNodeProcess(startInfo);
This ends up running a NodeJs server using the entrypoint-http.js script file (source). This has a lot of code, but it ends up creating a HTTP server that listens for requests that come out of calls to InvokeExportAsync.
The JavaScript function that is being invoked here, createWebpackDevServer (source), looks like this, with exception-handling removed for brevity:
export function createWebpackDevServer(callback) {
let aspNetWebpack = require('aspnet-webpack');
return aspNetWebpack.createWebpackDevServer.apply(this, arguments);
}
There's a lot of code for the createWebpackDevServer that is being invoked (source), so I won't include it here, but suffice to say it ends up running a connect server (source) that uses the webpack-dev-middleware (source).
I hope that gives enough of an explanation and a starting point for your own exploration.
The component’s state changes : A re-render can only be triggered if a component’s state has changed. The state can change from a props change, or from a direct setState change. The component gets the updated state and decides if it should re-render the component.
shouldComponentUpdate method : By default, shouldComponentUpdate returns true. That’s what causes the update everything all the time.

UWP - DataPackage.OperationCompleted is EMPTY & gets called by nobody

I'm writing a UWP file manager and I've come to a problem with drag&drop. I'm probably just beating my head against the wall since this is obviously another bug in the platform, but this time I can't find any workaround.
When dragging files and dropping them into File Explorer everything is fine. I fill up the DataPackage and listen to the OperationCompleted event, which happens when the files finished moving to another folder. When I drop them into another view within my app, I can call DataPackageView.ReportOperationCompleted, which does work (sort of). The problem is, it's also called AUTOMATICALLY at the same time the drop happens, even though the operation is not finished yet - and I can't do anything about it. The call stack is completely empty when I hit a breakpoint in the event handler.
On top of that, when I actually look into the arguments of OperationCompleted, the Operation in OperationCompletedEventArgs is ALWAYS None! It's None when File Explorer does the job, it's None when it gets called automatically, it's None when I call it manually, NO MATTER WHAT argument I pass in. Any explanation for this, Microsoft? I'm tired of fixing your bugs, especially when I can't actually do it since the platform is so limited.
one other "curiosity" with drag&dropping files in UWP is that if you get files dropped in your app and a requested operation set to move - you can't actually move them - the files are read-only. Try explaining that to the user.
Not sure how you to move files. In general, you should use StorageFile.CopyAsync method. You could use try/catch block to wrap this operation like the follwing:
try
{
var operation = appFile.File.CopyAsync(ApplicationData.Current.LocalFolder, appFile.File.DisplayName, NameCollisionOption.GenerateUniqueName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("exception msg: "+ex.Message);
}
Then if the file is readonly, you will get exception message, you should use this message to notify user.
I wanted a notification for when the operation is actually done.
You should implemente AsyncOperationWithProgressCompletedHandler for your async operation, then you will get notification when it's completed.
operation.Completed = (tresult,tprogress) => { System.Diagnostics.Debug.WriteLine("progress msg: "+tprogress); };

Categories