2012年1月28日土曜日

最近読んで、良かった本

ビッグデータ・ビジネスの時代」 北海道だと、まだまだIT化さえ進んでいない所が多いというのに、第1段階目のIT化されているレベル、第2段階目のIT化によってデータが集積できているレベル、第3段階目の集積されたデータを活用できているレベル、このうちの3段目のレベルのお話です。ほんの1年前までは、NoSQLやHadoopなんて、ちょっと毛色の変わった人の話という感じでした。しかし、最近では頻繁に、これらの事例を目にするように(ウェブ上)なりました。うちの社長には、ビッグデータ・ビジネスは、うちの会社のビジネスじゃないだろ・・・という風に言われました。半分は当たってますが、今から念頭に置いておかないと浦島太郎になりそうです。本書を読んで、そう思いました。この本を読む前から、データ実証主義の行き着く先は、この辺になるだろうから、どこかでビッグデータを取り扱う話にぶち当たる予感はありました。
グレイトフル・デッドにマーケティングを学ぶ」いやいや、凄いビジネス書です。万人にわかりやすく書かれていて、素晴らしい。今の時代のビジネスの本質をついてると思います。

どんどんと生産が海外に流れていくが…

もの作りの生産における人件費の占める割合って、いったい、いかほどのものなんだろうか?ソフトウェアのように、ほとんどが人件費のものならば、人件費が安いところで開発しようというのは、頷ける。酔っ払ってて、いまいち記憶が曖昧だが正月に自動車メーカーにいる友人と話てて、車のような大きいものでは、部品代と比較して人件費の割合なんて存外たいした事ないんじゃない?って聞いたような聞かないような・・・。  G+で知った「togetterにまとめきれなかった、グローバリゼーションの本質」にもあるように、世界の大衆車の販売を目指すのならば、やっぱり標準化してコストダウンしていかないと、お話にならないですよね?何が言いたいかというと、生産拠点を移しただけで勝てるとでも思ってるのかね?という事なんです。みんな、薄々そう感じながらも、コストダウン命で海外に生産拠点を移転ってやってるけど、本当に本質はそこですか?と、書いてみたかった。  競争するならスーパーカブのような車を作って、急須のようにデザイン性の高い民具レベルまで落とし込んだら、ロングセラーで商売してデザイン普遍で徹底的にコストを抑えるとか、逆に、もの凄いコンセプトカーを作って、ニッチな市場で高額販売するとか?  いや、どんどん生産拠点が海外に行ってる上に、NECが1万人削減とか、寂しい話が多いなーという訳で、書いてみました。

2012年1月24日火曜日

GeomagneticField に関する疑問

android のセンサーはカオスで、加速度系の方向が機種によって違うとか、いろいろ聞きます。 山をやる人には馴染みの磁北線ですが、国土地理院のページに詳しく書かれています。正確には測量によって算出されるもので、API に落としこむ Google は凄いなと思います。現在は時計回りを正とした場合、日本では反時計回り方向に磁北線があり、西偏X度というような表現をします。日本でも過去には東偏だった事があるようです。 さて、手持ちの機種 IS03, Regza AT3S0, Lenovo Ideapad K1 で検証したところ、方位は時計回りを正として表現されています。従って西偏として考えれば、北海道では9度ちょいなので時計回りを正とすれば、Android SDK の GeomagneticField.getIncrenation() で取得できるべき値は負であるべき気がしますが正。逆に GeomagneticField.getDeclination() で取得できる値は正であるべき気がするのですが負。API で取得できる値は正負が逆のような気がしてならない・・・。  もちろん、センサーで取得できる方位も時計回りが正なので、真北の補正は、
  magneticAngle - declination  // 間違い
  magneticAngle + inclination  // 間違い
だと思うのですが、ググッて見つかるのは magneticField + declination というものばかり・・・俺、間違ってるのかな・・・自信なくなってきた・・・。  ちなみに、SensorManager.remapCoordinateSystem から SensorManager.getOrientation の API を使って取得できる方位は単位がラジアンで、GeomagneticField.getDeclination で取得できる偏角は単位が度なので、注意が必要です。
2012/01/25 追記:  どうも、小学校からやり直しですな…。センサが方位0度を示している時、真北の値はX度な訳です。写像にすると、X度を0度にが補正写像な訳ですから、-X度を足し算すれば良い事になります。 従って、
  magneticAngle + declination  // 正解
  magneticAngle - inclination  // 正解
で良い事になります。あー、すっきりした。

2012年1月7日土曜日

あけおめー

皆さん、新年あけましておめでとうございます。
今年は嫁さんの実家に行って、その後、五色温泉~グスベリと、まわりました。

  お約束の五色温泉は、こんな感じです。










そして、坊ちゃんと、旧友の家族とで初滑りしたのですが、風が凄くて一本で敗退・・・。ほら、冬山に登ると空気が変わって、もの凄い厳しい風雪に見舞われる事があるじゃないですか?スキー場がそんな感じでした。旧友の坊ちゃん、うちの坊ちゃんより一歳年下なんですが、ちょっとだけ可哀想な感じでした…。

次はグスベリさんのところへ




ロケーションは、バッチシです。夜には、雪で寝かせた真狩村名産の百合根のグラタンが美味かった。







と、こんな感じの正月でした。

android 2重起動の禁止

いやー、android 開発、難しいですね~。こんな事は、もう語り尽くされているだろうと思ったかもしれませんが、もうちょい突っ込んだ内容になります。 android 関連の情報では、圧倒的にお世話になっている yanzm さんのところに Android launchMode の違いと、あるんで、基本は、これでオッケーなんです。  ところが、アプリケーションを終了して、直後に、アプリケーションを起動すると、一時的にアプリケーションというか、Activity が2重起動している状態になります。この時に初期化処理と終了処理が前後してしまう事があるんですわ。いやいや、ちゃんと行儀よくActivityを書いていれば、何の問題もないんです。どういう事をやっているかというと、
  
  ...
  class FooActivity extends Activity {
    public static Hoge hoge_ = null;
  ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      hoge_ = new Hoge();
    }
    @Override
    protected void onDestroy() {
      hoge_.close();
      super.onDestroy();
    }
  ...
  }
みたいな事をやってるんです。フッ、static な global 変数ですか?って笑われるかもしれませんが、正直、あちこちの Activity が関連を持って利用しなければならないとなると、こうするより他無いんです。こんなんで共有できてしまうのは、将来的に地雷を踏む可能性もあります。だって、アプリケーション全体でデータを共有するためには、どうしたらいいですか?に対する回答は、「ApplicationBean を使いましょう」だからです。データは、Parcelable で受け渡しすべきです。さて、この android.app.Application ですが、onDestroy に相当するメソッドがありません。正直言って使えません。また、画面の回転でレイアウトが変わる度に onDestroy と onCreate が呼ばれるので、うざくてしょうがありません。だから、私はダミーの BaseActivity を作成して、そこで共通リソースの初期化と破棄を行なってます。そうすれば、MainActivity の onDestroy と onCreate が何回呼ばれようが気にしなくて済みます。  話を巻き戻して、SingleTask なのに一時的に2重起動してもプロセスが別なら問題ないんじゃないですか?と思うやないですか?ところが、違うんです。この2つのアプリケーションから hoge_ が共有できてしまっており、先に終了したアプリの onDestroy よりも先に、後から起動したアプリの onCreate がコールされる状況があるんです。いや、もうビックリですね?しょうがないので、
  ...
  class FooActivity extends Activity {
    public static Hoge hoge_ = null;
    private static int process_count_ = 0;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      if( 0 == process_count_ ) {
        ++process_count_;
        hoge_ = new Hoge();
      } else {
        ++process_count_;
      }
    }
    @Override
    protected void onDestroy() {
      --process_count_;
      if( 0 == process_count_ ) {
        hoge_.close();
      }
      super.onDestroy();
    }
  ...
  }
という感じで、プロセス?カウントをとって、対処してます。ちなみにタイミングがシビアじゃ無いので、カウントの保護は一切行なっていません。 追記:static 変数の記述場所を間違えてたので修正しました。やっぱりカウンタは同期保護した方が良いかもしれません。synchronized(this)ではダメっぽい気がしますが、突っ込んでません。やるとすれば private static Object sync_ = new Object(); しておいて、synchronized(sync_) でしょうか?
訂正: final 修飾子が余計だったのを取った。
2012/01/15 追記: どうも、Activity 再開時の挙動など、singleTask 等で細かく異なるようである。参考になるサイトを見つけた。こちらも目を通した方が良いです。一旦 HOME ボタンを押した後に再開すると、singleTask では BaseActivity の onDestroy がコールされるので思わしくない。そこで、このような事をやる場合は、singleInstance を選択する事にしました。 singleInstance は、Activity のフォーカスが外れる時点で、onDestroy がコールされ破棄されるので、使えない。別に single である必要は無い気がしてきた…。もう少し突っ込んで、整理した後に書く予定。追試する度に、挙動が違って困る…。
 2012/01/17 追記: BaseActivity に Manifest で android:screenOrientation="landscape" と指定するようにした。 BaseActivity -> MainActivity と表示している時にレイアウトの縦横が変更された時、MainActivity だけが変更の影響を受けるわけではなく、BaseActivity にまで変更の影響を受けている事がわかった。そのせいで、BaseActivity の onDestroy と onCreate がコールされる事になる。この辺の挙動は、かなりトリッキーだ。BaseActivity の onCreate 時に MainActivity を起動しているのだが、MainActivity が縦横変更時にどんどん増殖するという恐ろしい事態を引き起こしていた。現在は、singleInstance で実装している。
2012/08/29 追記:Android SDK における sqlite3 のコードが、データベースを開いたプロセスと閉じたプロセスが同一でないと、エラーで動作しないようなチェックが入っております。なので、最終的には、2重起動を自前で禁止するために、process_count_ >= 2 ならば、アプリケーションを終了するようにしました。  一方のプロセスがデータベースを閉じるまで待ってからオープンしようと synchronized メソッドでカウントを検知したら、そこから抜けてThread.sleep(200); とか入れてみたんですが、プロセス|スレッドのコンテキストが全く切り替わりません。このため、2重起動を自前で防ぐコードを選択せざるを得ませんでした。こういうのは、singleInstance を指定しているんだから、アプリがやる仕事じゃ無いと思います。