rksoftware

Visual Studio とか C# とかが好きです

タイマーの精度について (2)

Xamarin.Forms で一定間隔の時間毎に何か処理をしたい場合、Xamarin.Forms.Device クラスの StartTimer メソッドが使えます。
しかし、精度はそれほど高くはありません。
※ Xamarin.Forms に限らず、他の環境でも普通精度は高くないです
比較的シンプルな1 秒( 1,000 ミリ秒)毎に経過ミリ秒をコンソールに表示するコードを以前に書きました。

上記コードは、十分な動作はするものの端末への負荷をもう少し下げられそうです。
というわけで、少々難しいコードになりますが、もう一つの戦略です。

概要としては毎回タイマー間隔を計算していい感じの間隔設定し続けるものです。

■ コード

public MainPage()
{
    InitializeComponent();

    var count = 0;
    var stopWatch = System.Diagnostics.Stopwatch.StartNew();
    var lastElapsed = 0L;

    Func<bool> func = null;
    func = () =>
    {
         ++count;
         var millisec = stopWatch.ElapsedMilliseconds;
         System.Console.WriteLine($"> {count.ToString("000")} {millisec.ToString("000,000")} +{(millisec - lastElapsed).ToString()}  ");

         if (millisec > 100_000) return false;
         lastElapsed = millisec;

         var span = millisec % 1_000;
         Device.StartTimer(TimeSpan.FromMilliseconds(1_000 - span), func);
         return false;
    };
    func();
}

タイマーで実行したい処理を func にとり、再帰的にタイマーを起動し実行しています。
タイマーは毎回一回しか動作しないので、return 値は必ず false になっています。
ポイントは毎回のタイマーの TimeSpan の設定で、計算により次の秒までの間隔を求めて設定しています。

■ 実行結果

────────────────────
回  経過   前回からの経過
────────────────────
001 000,001 +1
002 001,053 +1052
003 002,002 +949
004 003,004 +1002
005 004,005 +1001
006 005,004 +999
007 006,005 +1001
008 007,004 +999
009 008,005 +1001
010 009,003 +998
011 010,006 +1003
012 011,006 +1000
013 012,005 +999
014 013,005 +1000
015 014,006 +1001
016 015,005 +999
017 016,005 +1000
018 017,005 +1000
019 018,006 +1001
020 019,005 +999
021 020,005 +1000
022 021,006 +1001
023 022,006 +1000
024 023,005 +999
025 024,006 +1001
026 025,005 +999
027 026,005 +1000
028 027,005 +1000
029 028,006 +1001
030 029,005 +999
031 030,004 +999
032 031,005 +1001
033 032,005 +1000
034 033,004 +999
035 034,005 +1001
036 035,006 +1001
037 036,007 +1001
038 037,002 +995
039 038,002 +1000
040 039,004 +1002
041 040,005 +1001
042 041,006 +1001
043 042,005 +999
044 043,005 +1000
045 044,004 +999
046 045,002 +998
047 046,006 +1004
048 047,006 +1000
049 048,004 +998
050 049,006 +1002
051 050,004 +998
052 051,005 +1001
053 052,004 +999
054 053,006 +1002
055 054,005 +999
056 055,005 +1000
057 056,004 +999
058 057,006 +1002
059 058,005 +999
060 059,005 +1000
061 060,005 +1000
062 061,005 +1000
063 062,005 +1000
064 063,004 +999
065 064,006 +1002
066 065,006 +1000
067 066,005 +999
068 067,006 +1001
069 068,004 +998
070 069,005 +1001
071 070,005 +1000
072 071,005 +1000
073 072,005 +1000
074 073,004 +999
075 074,005 +1001
076 075,005 +1000
077 076,005 +1000
078 077,005 +1000
079 078,005 +1000
080 079,004 +999
081 080,006 +1002
082 081,005 +999
083 082,005 +1000
084 083,006 +1001
085 084,005 +999
086 085,006 +1001
087 086,005 +999
088 087,005 +1000
089 088,005 +1000
090 089,005 +1000
091 090,004 +999
092 091,002 +998
093 092,002 +1000
094 093,006 +1004
095 094,005 +999
096 095,006 +1001
097 096,005 +999
098 097,005 +1000
099 098,005 +1000
100 099,005 +1000
101 100,005 +1000

かなり良い結果が得られました。
しかし、理屈が難しく、処理が複雑であることが難点です。一度はうまく動いても後のメンテナンスで不慣れなプログラマーが手を入れた際にバグを出してしまう可能性は決して低くはないと思います。

■ 状況により適した方法を

どの方法にも良いところはあります。状況に合わせてその時々最適な方法を選択することがおすすめです。