2018年4月16日月曜日

Xamarin の C# の Android Framework でメニューを使うには?

 Xamarin + Android Framework でアプリ開発中、Menu の追加にてこずった。
 
 後からメニューを追加しようとして、ネットで探した

public override Boolean OnCreateOptionsMenu (IMenu menu)
{
    MenuInflater.Inflate(Resource.Menu.mymenu, menu);
    return base.OnPrepareOptionsMenu(menu);
}

をコピペしたのだが

エラー CS0115 'xxxActivity.OnCreateOptionsMenu(IMenu)': オーバーライドする適切なメソッドが見つかりませんでした。 

エラー CS0246 型または名前空間の名前 'IMenu' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)。

とエラーが出る。

OnCreateOptionsMenu() は、Android Framework のメソッドそのままなのに、見つかりませんってどういうこと?と悩むこと10数分。名前空間の指定が足りないのは IMenu の方だった

using Android.Views;

を追加して一件落着。

VS のコード補完は Android Studio より弱いのか。


2017年8月7日月曜日

xrea の crontab

Python で作った Web サービスを xrea にデプロイしているのだが、crontab で嵌った。

1.実行結果のメールが来たり来なかったり
  crontab で処理が実行された後には 「結果・エラーメール(stdout と stderr に吐き出された内容)」が届くはずなのだが、届いたり届かなかったり

2.実行されるのは一時間に一回
 「ジョブの間隔は最短で1時間に1回とさせて頂いております」と明記されているのだが、crontab の設定で一時間に2回以上回る場合は、と解釈していたのだが違うようだ。
 crontab には 30件(スロット)設定できるのだが、手作業で起動時刻を設定しなおしても、一つのスロットにつき一時間に二回以上は実行しない様子。実行されるスクリプトを手直しして、再実行させようとして同じスロットで起動時刻を変更しても、最初に実行した時刻から一時間経過しないと実行されない。
 一時間ほど嵌って、あきらめて寝て、布団の中で気が付いた。

2017年1月3日火曜日

Xmarin+Android framework で RunOnUiThread() を使うとデータが化けた話

 Xmarin+Android framework でシステム開発中。

 ストリーミングのデータを処理し、エラーを見つけたらリアルタイムに画面に表示する機能を実装していた。

 表示にはエラーが発生した時刻(ms まで)と期待したデータと実際に受信したデータを表示するようにしたのだが、期待したデータの表示が、こちらが期待した値にならない。データ処理ロジックが間違っているのかと数時間ソースを追ったのだが原因がつかめない。

(ちなみに、どういうわけかブレークポイントが使えない。設定するとプログラムが止まるタイミングでアプリが終了する)

 いろいろやっていくうちに、「画面表示だと、別スレッドだから時間表示がずれる。ログに吐かせてみよう」ということで、同じ内容をログにはかせると期待したデータが表示された!

----
 原因だが、RunOnUiThread() に渡したコードに、クラス内で定義した変数を持たせたために、表示スレッドが実行される前にその変数が更新されてしまうことが原因だった。

class foo
  {
  int LastData;

  void bar (int data)
  {
    ....
    parentActivity.RunOnUiThread(() =>
    {
      parentActivity.UpdateTestInfo("Error Info: " + DateTime.Now.ToString("HH:mm:ss.fff") + ":" + LastData.ToString("x2") + "-" + data.ToString("x2") + "\n");
    }
  }

 というようなコードを書いたのだが、コードが UiThread のキューに積まれるときに、

  • date は関数終了と同時に消滅するローカル変数だから値渡し
  • LastData は、関数が終了しても消滅しないので参照渡し
となったらしい。

 ストリーミングデータを処理しているため LastData は常に更新されていく。そのため画面に表示されるのは、RunOnUiThread() が実行された時点での LastData の値ではなく parentActivity.UpdateTestInfo(...)が実行されるときの LastData の値、
 date の方は値渡しなのでRunOnUiThread() が実行された時の値に。

 変数は参照わたしなんかしないで、キューに積む時点の値で全部値渡しにしてしまえばいいのに。

 

2016年11月25日金曜日

Xamarin の C# の Android には Java.Lang.Object というクラスがある

 Xamarin を Android フレームワークで使っていて、ListView を操作するために View の setTag(), getTag() を使おうとしたのだだが、どうもうまくいかない。

 holder のクラスが Java.Lang.Object にキャストできないと文句を言われる。

 いろいろ調べった結果、holder のクラスを、Java.Lang.Object クラスを継承させれば OK と解った。

 C# に Java.Lang.Object なんてクラスを使うのは、ちょっと気が付かなかった。

参考サイト