summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradrianknight89 <adrianknight89@outlook.com>2017-01-10 18:07:01 -0600
committerJason Smith <jason.smith@xamarin.com>2017-01-10 16:07:01 -0800
commitf78b328759bb673b695c6b0d1a1dac6d871d257a (patch)
tree53af7ed6bce1b2287ba7addd89f782dd4606d7c6
parentdcea6b4853f76dbc4661c42c56244e0a70d889ed (diff)
downloadxamarin-forms-f78b328759bb673b695c6b0d1a1dac6d871d257a.tar.gz
xamarin-forms-f78b328759bb673b695c6b0d1a1dac6d871d257a.tar.bz2
xamarin-forms-f78b328759bb673b695c6b0d1a1dac6d871d257a.zip
iOS and Android timers should be runnable from any thread and execute… (#374)
* iOS and Android timers should be runnable from any thread and executed on the main thread * removing unused Timer class declarations with minor refactoring efforts * iOS and Android timers should be runnable from any thread and executed on the main thread * removing bak file * switch to v7 * add test code
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs116
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems1
-rw-r--r--Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs51
-rw-r--r--Xamarin.Forms.Core/ITimer.cs13
-rw-r--r--Xamarin.Forms.Core/Xamarin.Forms.Core.csproj1
-rw-r--r--Xamarin.Forms.Platform.Android/Forms.cs53
-rw-r--r--Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs30
-rw-r--r--Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs39
-rw-r--r--Xamarin.Forms.Platform.iOS/Forms.cs56
9 files changed, 136 insertions, 224 deletions
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs
new file mode 100644
index 00000000..3a357863
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs
@@ -0,0 +1,116 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System;
+using System.Threading.Tasks;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Bugzilla, 28953, "Device.StartTimer (still) behaves differently on different platforms", PlatformAffected.All)]
+ public class Bugzilla28953 : TestContentPage // or TestMasterDetailPage, etc ...
+ {
+ int count = 0, count2 = 0;
+ Label label2, label3;
+ bool shouldStop, shouldStop2;
+
+ protected override void Init()
+ {
+ var stackLayout = new StackLayout
+ {
+ Orientation = StackOrientation.Vertical,
+ VerticalOptions = LayoutOptions.Center,
+ Spacing = 20
+ };
+
+ var label1 = new Label
+ {
+ Text = "Click Start to start counting with a timer. Click Stop to reset. Both timers update text in UI thread."
+ };
+ stackLayout.Children.Add(label1);
+
+ label2 = new Label
+ {
+ Text = count.ToString(),
+ HorizontalTextAlignment = TextAlignment.Center,
+ };
+ stackLayout.Children.Add(label2);
+
+ label3 = new Label
+ {
+ Text = count2.ToString(),
+ HorizontalTextAlignment = TextAlignment.Center,
+ };
+ stackLayout.Children.Add(label3);
+
+ var button = new Button
+ {
+ Text = "Start"
+ };
+ button.Clicked += Button_Clicked;
+ stackLayout.Children.Add(button);
+
+ var button2 = new Button
+ {
+ Text = "Start (in background thread)"
+ };
+ button2.Clicked += Button_Clicked2;
+ stackLayout.Children.Add(button2);
+
+ Content = stackLayout;
+ }
+
+ private void Button_Clicked(object sender, EventArgs e)
+ {
+ var button = sender as Button;
+ if (button.Text == "Start")
+ {
+ (sender as Button).Text = "Stop";
+ shouldStop = false;
+
+ Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
+ {
+ label2.Text = count.ToString();
+ count++;
+ return !shouldStop;
+ });
+ }
+ else
+ {
+ button.Text = "Start";
+ shouldStop = true;
+ count = 0;
+ }
+ }
+
+ private void Button_Clicked2(object sender, EventArgs e)
+ {
+ var button = sender as Button;
+ if (button.Text == "Start (in background thread)")
+ {
+ (sender as Button).Text = "Stop (in background thread)";
+ shouldStop2 = false;
+
+ Task.Run(() =>
+ {
+ Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
+ {
+ label3.Text = count2.ToString();
+ count2++;
+ return !shouldStop2;
+ });
+ });
+ }
+ else
+ {
+ button.Text = "Start (in background thread)";
+ shouldStop2 = true;
+ count2 = 0;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 36ed04cb..16a2199d 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -36,6 +36,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla28570.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla28796.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla28939.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28953.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla29107.xaml.cs">
<DependentUpon>Bugzilla29107.xaml</DependentUpon>
</Compile>
diff --git a/Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs b/Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs
index 5109cbb4..e8519b9e 100644
--- a/Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs
+++ b/Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs
@@ -119,57 +119,6 @@ namespace Xamarin.Forms.Core.UnitTests
return AppDomain.CurrentDomain.GetAssemblies ();
}
- public ITimer CreateTimer (Action<object> callback)
- {
- return new MockTimer (new Timer (o => callback(o)));
- }
-
- public ITimer CreateTimer (Action<object> callback, object state, int dueTime, int period)
- {
- return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
- }
-
- public ITimer CreateTimer (Action<object> callback, object state, long dueTime, long period)
- {
- return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
- }
-
- public ITimer CreateTimer (Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
- {
- return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
- }
-
- public ITimer CreateTimer (Action<object> callback, object state, uint dueTime, uint period)
- {
- return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
- }
-
- public class MockTimer : ITimer
- {
- readonly Timer timer;
- public MockTimer (Timer timer)
- {
- this.timer = timer;
- }
-
- public void Change (int dueTime, int period)
- {
- timer.Change (dueTime, period);
- }
- public void Change (long dueTime, long period)
- {
- timer.Change (dueTime, period);
- }
- public void Change (TimeSpan dueTime, TimeSpan period)
- {
- timer.Change (dueTime, period);
- }
- public void Change (uint dueTime, uint period)
- {
- timer.Change (dueTime, period);
- }
- }
-
public IIsolatedStorageFile GetUserStoreForApplication ()
{
#if WINDOWS_PHONE
diff --git a/Xamarin.Forms.Core/ITimer.cs b/Xamarin.Forms.Core/ITimer.cs
deleted file mode 100644
index ba867dba..00000000
--- a/Xamarin.Forms.Core/ITimer.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace Xamarin.Forms
-{
- //this will go once Timer is included in Pcl profiles
- internal interface ITimer
- {
- void Change(int dueTime, int period);
- void Change(long dueTime, long period);
- void Change(TimeSpan dueTime, TimeSpan period);
- void Change(uint dueTime, uint period);
- }
-} \ No newline at end of file
diff --git a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
index 9bfb7ba2..2e10a1b2 100644
--- a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
+++ b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
@@ -369,7 +369,6 @@
<Compile Include="Tweener.cs" />
<Compile Include="IPlatformServices.cs" />
<Compile Include="UriTypeConverter.cs" />
- <Compile Include="ITimer.cs" />
<Compile Include="IIsolatedStorageFile.cs" />
<Compile Include="Grid.cs" />
<Compile Include="GridCalc.cs" />
diff --git a/Xamarin.Forms.Platform.Android/Forms.cs b/Xamarin.Forms.Platform.Android/Forms.cs
index 3d2a735c..1ecf76d3 100644
--- a/Xamarin.Forms.Platform.Android/Forms.cs
+++ b/Xamarin.Forms.Platform.Android/Forms.cs
@@ -410,22 +410,15 @@ namespace Xamarin.Forms
public void StartTimer(TimeSpan interval, Func<bool> callback)
{
- Timer timer = null;
- bool invoking = false;
- TimerCallback onTimeout = o =>
+ var handler = new Handler(Looper.MainLooper);
+ handler.PostDelayed(() =>
{
- if (!invoking)
- {
- invoking = true;
- BeginInvokeOnMainThread(() =>
- {
- if (!callback())
- timer.Dispose();
- invoking = false;
- });
- }
- };
- timer = new Timer(onTimeout, null, interval, interval);
+ if (callback())
+ StartTimer(interval, callback);
+
+ handler.Dispose();
+ handler = null;
+ }, (long)interval.TotalMilliseconds);
}
double ConvertTextAppearanceToSize(int themeDefault, int deviceDefault, double defaultValue)
@@ -472,36 +465,6 @@ namespace Xamarin.Forms
return false;
}
- public class _Timer : ITimer
- {
- readonly Timer _timer;
-
- public _Timer(Timer timer)
- {
- _timer = timer;
- }
-
- public void Change(int dueTime, int period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(long dueTime, long period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(TimeSpan dueTime, TimeSpan period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(uint dueTime, uint period)
- {
- _timer.Change(dueTime, period);
- }
- }
-
public class _IsolatedStorageFile : IIsolatedStorageFile
{
readonly IsolatedStorageFile _isolatedStorageFile;
diff --git a/Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs b/Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs
index 30623088..cd9f44f9 100644
--- a/Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs
+++ b/Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs
@@ -137,36 +137,6 @@ namespace Xamarin.Forms
return 'a' + v - 10;
}
- public class _Timer : ITimer
- {
- readonly Timer _timer;
-
- public _Timer(Timer timer)
- {
- _timer = timer;
- }
-
- public void Change(int dueTime, int period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(long dueTime, long period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(TimeSpan dueTime, TimeSpan period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(uint dueTime, uint period)
- {
- _timer.Change(dueTime, period);
- }
- }
-
public class _IsolatedStorageFile : IIsolatedStorageFile
{
readonly IsolatedStorageFile _isolatedStorageFile;
diff --git a/Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs b/Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs
index 49589a8a..310b66c3 100644
--- a/Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs
+++ b/Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs
@@ -29,12 +29,12 @@ namespace Xamarin.Forms.Platform.WinRT
{
internal abstract class WindowsBasePlatformServices : IPlatformServices
{
- CoreDispatcher _dispatcher;
+ readonly CoreDispatcher _dispatcher;
- public WindowsBasePlatformServices(CoreDispatcher dispatcher)
+ protected WindowsBasePlatformServices(CoreDispatcher dispatcher)
{
if (dispatcher == null)
- throw new ArgumentNullException("dispatcher");
+ throw new ArgumentNullException(nameof(dispatcher));
_dispatcher = dispatcher;
}
@@ -57,9 +57,8 @@ namespace Xamarin.Forms.Platform.WinRT
IReadOnlyList<StorageFile> files = query.GetFilesAsync().AsTask().Result;
var assemblies = new List<Assembly>(files.Count);
- for (var i = 0; i < files.Count; i++)
+ foreach (StorageFile file in files)
{
- StorageFile file = files[i];
try
{
Assembly assembly = Assembly.Load(new AssemblyName { Name = Path.GetFileNameWithoutExtension(file.Name) });
@@ -133,35 +132,5 @@ namespace Xamarin.Forms.Platform.WinRT
timer.Stop();
};
}
-
- internal class WindowsTimer : ITimer
- {
- readonly Timer _timer;
-
- public WindowsTimer(Timer timer)
- {
- _timer = timer;
- }
-
- public void Change(int dueTime, int period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(long dueTime, long period)
- {
- Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period));
- }
-
- public void Change(TimeSpan dueTime, TimeSpan period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(uint dueTime, uint period)
- {
- Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period));
- }
- }
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.iOS/Forms.cs b/Xamarin.Forms.Platform.iOS/Forms.cs
index 06cb1312..5361e13f 100644
--- a/Xamarin.Forms.Platform.iOS/Forms.cs
+++ b/Xamarin.Forms.Platform.iOS/Forms.cs
@@ -68,9 +68,7 @@ namespace Xamarin.Forms
internal static void SendViewInitialized(this VisualElement self, UIView nativeView)
{
- var viewInitialized = ViewInitialized;
- if (viewInitialized != null)
- viewInitialized(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
+ ViewInitialized?.Invoke(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
}
class iOSExpressionSearch : ExpressionVisitor, IExpressionSearch
@@ -117,15 +115,9 @@ namespace Xamarin.Forms
public override Size PixelScreenSize { get; }
- public override Size ScaledScreenSize
- {
- get { return _scaledScreenSize; }
- }
+ public override Size ScaledScreenSize => _scaledScreenSize;
- public override double ScalingFactor
- {
- get { return _scalingFactor; }
- }
+ public override double ScalingFactor => _scalingFactor;
protected override void Dispose(bool disposing)
{
@@ -136,7 +128,7 @@ namespace Xamarin.Forms
class IOSPlatformServices : IPlatformServices
{
- static readonly MD5CryptoServiceProvider Checksum = new MD5CryptoServiceProvider();
+ static readonly MD5CryptoServiceProvider s_checksum = new MD5CryptoServiceProvider();
public void BeginInvokeOnMainThread(Action action)
{
@@ -155,7 +147,7 @@ namespace Xamarin.Forms
public string GetMD5Hash(string input)
{
- var bytes = Checksum.ComputeHash(Encoding.UTF8.GetBytes(input));
+ var bytes = s_checksum.ComputeHash(Encoding.UTF8.GetBytes(input));
var ret = new char[32];
for (var i = 0; i < 16; i++)
{
@@ -198,10 +190,7 @@ namespace Xamarin.Forms
return new _IsolatedStorageFile(IsolatedStorageFile.GetUserStoreForApplication());
}
- public bool IsInvokeRequired
- {
- get { return !NSThread.IsMain; }
- }
+ public bool IsInvokeRequired => !NSThread.IsMain;
public void OpenUriAction(Uri uri)
{
@@ -210,8 +199,7 @@ namespace Xamarin.Forms
public void StartTimer(TimeSpan interval, Func<bool> callback)
{
- NSTimer timer = null;
- timer = NSTimer.CreateRepeatingScheduledTimer(interval, t =>
+ NSTimer timer = NSTimer.CreateRepeatingTimer(interval, t =>
{
if (!callback())
t.Invalidate();
@@ -238,36 +226,6 @@ namespace Xamarin.Forms
return 'a' + v - 10;
}
- public class _Timer : ITimer
- {
- readonly Timer _timer;
-
- public _Timer(Timer timer)
- {
- _timer = timer;
- }
-
- public void Change(int dueTime, int period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(long dueTime, long period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(TimeSpan dueTime, TimeSpan period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(uint dueTime, uint period)
- {
- _timer.Change(dueTime, period);
- }
- }
-
public class _IsolatedStorageFile : IIsolatedStorageFile
{
readonly IsolatedStorageFile _isolatedStorageFile;