My Photo

« September 2011 | Main | November 2011 »

October 31, 2011

FF11 シーフでアットワスラッグNMに挑んだ

昨日、召(負けた)や赤(勝った)でやったことのあるアットワのスラッグNM「Berstu」をシ/踊でやってみた。
メイン踊だかサポ踊だか忘れたけど「ガとジャをVフラリッシュで止めれば難しくない」みたいに書いてあるのをどこかで読んだ気がするので。

アートマは紫苑、灰燼、終焉を付けた。
湧かしてすぐにとんずらで逃げる、つもりだったが、モタモタしてたらウォタガだかウォタジャ喰らってしまったorz
#今考えると、逃げなくても湧いたらすぐにVフラ入れればいいのか^^;
なんとか立て直して、そのごもたまにガやジャを喰らったが、倒すことができた。薬品はルシドポーション1と2を使用。戦闘時間は赤でマラソンするよりずっと短かった。型紙はカリスが1枚。残念。
ガとジャは止められた方がもちろんいいが、完全に止められなくてもなんとかなる。TPは結構貯まるのでケアルワルツ3で立て直せる。
それよりかファスカスウーズの装備不可の方が怖い。素手になるので攻撃が当たらずHPが減る一方になる。

伊賀型紙:頭が欲しいからちょくちょく倒しに行くことにしよう。
それに何度ももやっていればそのうちアートマも手にはいるかもしれないし。

October 30, 2011

Androidアプリ開発メモ033:サービス その5:Messengerを使用したバインドされたサービス

サービスについての以前の記事:
Androidアプリ開発メモ021:サービス
Androidアプリ開発メモ030:サービス その2
Androidアプリ開発メモ031:サービス その3:IntentService
Androidアプリ開発メモ032:サービス その4:バインドされたサービス

Messengerの利用

異なるプロセスから利用できるサービスは、Messengerを使って実装することができる。
コンポーネントクライアントがサービスと異なるプロセスの場合、コンポーネントクライアントでServiceConnection#onServiceConnected()のIBinderを使ってもサービスの参照を得ることはできない。
なのでクライアントコンポーネントがサービスのメソッドを呼び出すのではなく、MessengerとHandlerでMessageを相互にやり取りする。
具体的には以下のようにする。

  • サービスでクライアントからそれぞれのコールバックを受け取るHandlerを実装する。
  • HandlerはMessengerオブジェクト(これはHandlerへの参照となる)を作成するために使用される。
  • MessengerはサービスがonBind()からクライアントに返すIBinderを作成する。
  • クライアントはIBinderを使ってクライアントがMessageオブジェクトをサービスに送信するために使用するMessenger(サービスのハンドラのHandler参照となる)をインスタンス化する。
  • サービスはそのHandler、具体的にはhandleMessage()メソッドで、それぞれのMessagerを受け取る。

MessengerとHandler

Handlerを指すMessengerを作成し、Messengerを別のプロセスに渡すことによってプロセス間の通信をすることができる。

android.os.Messengerクラスのコンストラクタ・メソッド

public Messenger(Handler target)
与えられたHandlerを指す新しいMessengerを作成する。

public Messenger (IBinder target) 
raw IBinder からMessengerを作成する。IBinderはgetBinder()で明白に読み出されたものである。

public IBinder getBinder()
このMessengerが関連するHandlerと通信するために使うIBinderを読み出す。

public void send(Message message)
このMessengerのHandlerへMessageを送信する。

android.os.Handlerクラスのメソッド
public void handleMessage(Message msg)
サブクラスはメッセージを受けるようにこれを実装しなければならない。

Message

MessageはMessengerからHandlerに送られるデータのクラスである。
追加の2つのintフィールド、追加のオブジェクトのフィールドがある。多くのケースでこれらの追加のフィールドは割り当てをしなくてもよい。

主なフィールド

public int arg1
public int arg2
public Object obj
public Messenger replyTo このメッセージへの返信が送られる任意のMessenger(?)
pulic int what 受信者がこのメッセージがなんについてであるか識別できるユーザー定義メッセージコード

public static Message obtain()
新しいMessageインスタンスをglobal poolから作成する。多くの場合、新しいオブジェクトの割り当てを回避することを許す。

public static Message obtain(Handler h, int what, int arg1, int arg2)
obtain()と同じだが、ターゲット、what、arg1、arg2メンバーをセットする。

ApiDemoの com.example.android.apis.app.MessengerService の概要は以下。
  • Handlerを作り、
  • そのHandlerをコンストラクタの引数にしてMessengerを作り、
  • onBind()は、そのMessengerのgetBinder()の戻りのIBinderを返している

ApiDemoの com.example.android.apis.app.MessengerServiceActivity の概要は以下。
  • Handlerを作り、
  • そのHandlerをコンストラクタの引数にしてMessenger(replyTo用)を作る
  • onServiceConnected()が呼ばれると、引数のIBinderをコンストラクタの引数にしてMessenger(送信用)を作り、このMessengerでメッセージを2つ送る。1つはクライアント登録コマンドでreplyToにMessenger(replyTo用)をセットしている。もう1つは値登録コマンドでreplyToには何もセットしていない。

以下、ApiDemoのMessengerService.javaとMessengerServiceActivityのコード。コメント、import、パッケージ名など少し変えている。
package com.example.messengerserviceexample;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;

import java.util.ArrayList;

/**
 * API Demoのコードほぼそのまま。
 * コメントを削ったり、import文を削っただけ。 
 */
public class MessengerService extends Service {

  NotificationManager mNM;
  /** 登録されたクライアントのメッセンジャーを保持するリスト */
  ArrayList mClients = new ArrayList();
  /** クライアントにセットされた最後の値を保持する */
  int mValue = 0;
  
  /**
   * サービスにクライアント登録コマンド。クライアントはサービスからコールバックを受信する。
   * メッセージのreplyToフィールドはクライアントのメッセンジャーでなければならない。
   * このサービスをバインドする別のアプリのためにpublicにした。
   */
  public static final int MSG_REGISTER_CLIENT = 1;
  
  /**
   * サービスにクライアント登録解除コマンド。クライアントはサービスからのコールバック受信を止める。
   * メッセージのreplyToフィールドはクライアントのメッセンジャーでなければならない。
   * このサービスをバインドする別のアプリのためにpublicにした。
   */
  public static final int MSG_UNREGISTER_CLIENT = 2;
  
  /**
   * サービスに値セットコマンド。新しい値を供給するためにこれはサービスに送られる。
   * そして新しい値とともに登録されたクライアントどれでもサービスによって送られる。
   * このサービスをバインドする別のアプリのためにpublicにした。
   */
  public static final int MSG_SET_VALUE = 3;
  
  /**
   * クライアントからやってくるメッセージのハンドラ
   */
  class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case MSG_REGISTER_CLIENT:
        // replyToのメッセンジャーをリストに追加する
        mClients.add(msg.replyTo);
        Log.v("MESSENGER_SERVICE", "MSG_REGISTER_CLIENT:replyTo=" + msg.replyTo);
        break;
      case MSG_UNREGISTER_CLIENT:
        // replyToのメッセンジャーをリストから削除する
        mClients.remove(msg.replyTo);
        Log.v("MESSENGER_SERVICE", "MSG_UNREGISTER_CLIENT:replyTo=" + msg.replyTo);
        break;
      case MSG_SET_VALUE:
        // 送られてきた値を登録されているすべてのクライアントに送る
        mValue = msg.arg1;
        Log.v("MESSENGER_SERVICE", "MSG_SET_VALUE:replyTo=" + msg.replyTo);
        for (int i = mClients.size() - 1; i >= 0; i--) {
          try {
            mClients.get(i).send(
                Message.obtain(null, MSG_SET_VALUE, mValue, 0));
          } catch (RemoteException e) {
            // クライアントが死んでいる。それをリストから除去する。
            // ループの内側でしても安全なようにリストを後ろから前に通過する。
            mClients.remove(i);
          }
        }
        break;
      default:
        super.handleMessage(msg);
      }
    }
  }
  
  /**
   * クライアントのために公開しているターゲット(?)、IncomingHandlerにメッセージを送る。
   */
  final Messenger mMessenger = new Messenger(new IncomingHandler());
  
  @Override
  public void onCreate() {
    Log.v("MESSENGER_SERVICE", "onCreate()");
    
    mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    // 開始のノーティフィケーションを表示
    showNotification();
  }

  @Override
  public void onDestroy() {
    Log.v("MESSENGER_SERVICE", "onDestroy()");
    
    // 永続的なノーティフィケーションをキャンセル
    mNM.cancel(R.string.remote_service_started);

    // 停止を伝える
    Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();
  }
  
  /**
   * サービスにバインドするとき、サービスへメッセージを
   * 送るためのメッセンジャーへのインターフェースを返す。
   */
  @Override
  public IBinder onBind(Intent intent) {
    Log.v("MESSENGER_SERVICE", "onBind()");
    
    return mMessenger.getBinder();
  }

  /**
   * サービスが動作している間ノーティフィケーションを表示する。
   */
  private void showNotification() {
    // このサンプルでは、tickerとexpanded notificationで同じでテキストを使う
    CharSequence text = getText(R.string.remote_service_started);

    // アイコン、スクロールするテキスト、タイムスタンプをセット
    Notification notification
      = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis());

    // ユーザーがこのノーティフィケーションを選択した場合にアクティビティをランチするPendingIntent
    PendingIntent contentIntent
      = PendingIntent.getActivity(this, 0,
          new Intent(this, MessengerServiceActivity.class), 0);

    // ノーティフィケーションパネルで表示するビューの情報をセットする
    notification.setLatestEventInfo(this, getText(R.string.remote_service_label),
        text, contentIntent);

    // ノーティフィケーションを送る
    // 我々は文字列IDを使用する。なぜならそれはユニークな数だからだ。後でキャンセルするときにそれを使用する。
    mNM.notify(R.string.remote_service_started, notification);
  }
}

package com.example.messengerserviceexample;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

/**
 * API Demoのコードほぼそのまま。
 * 元のコードはpublic static な入れ子クラスでAcitivityを実装していたが
 * 入れ子じゃない外側のクラスにした。
 */
public class MessengerServiceActivity extends Activity {
  
  /** サービスと通信するためのメッセンジャー */
  Messenger mService = null;
  /** サービスにバインドを呼んだかを示すフラグ */
  boolean mIsBound;
  /** 状態を表示するためのテキストビュー */
  TextView mCallbackText;
  
  /**
   * サービスからやってくるメッセージのハンドラ
   */
  class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case MessengerService.MSG_SET_VALUE:
        mCallbackText.setText("Received from service: " + msg.arg1);
        break;
      default:
        super.handleMessage(msg);
      }
    }
  }
  
  /**
   * クライアントがIncomingHandlerにメッセージを送るターゲット、われわれが公開した(?)
   */
  final Messenger mMessenger = new Messenger(new IncomingHandler());
        
  /**
   * サービスのメインインタフェースと相互に作用するためのクラス
   */
  private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
        IBinder service) {
      
      mService = new Messenger(service);
      mCallbackText.setText("Attached.");

      // サービスと接続している限りサービスを監視したい
      try {
        Message msg = Message.obtain(null,
            MessengerService.MSG_REGISTER_CLIENT);
        msg.replyTo = mMessenger;
        mService.send(msg);
        
        // 例としてある値を与える
        msg = Message.obtain(null,
            MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
        mService.send(msg);
      } catch (RemoteException e) {
      }
      
      // サンプルの一環として、何が起きたかユーザーに表示する
      Toast.makeText(MessengerServiceActivity.this, R.string.remote_service_connected,
          Toast.LENGTH_SHORT).show();
    }
    
    public void onServiceDisconnected(ComponentName className) {
      // これはサービスのコネクションが不意に切断された場合
      // -- すなわちプロセスがクラッシュした場合に呼ばれる。
      mService = null;
      mCallbackText.setText("Disconnected.");
      
      // サンプルの一環として、何が起きたかユーザーに表示する
      Toast.makeText(MessengerServiceActivity.this, R.string.remote_service_disconnected,
          Toast.LENGTH_SHORT).show();
    }
  };
  
  void doBindService() {
    // サービスのコネクションを確立する。明示的なクラス名を使う。
    // なぜなら他のアプリケーションが私たちのコンポーネントを
    // 交換できるようにできるようにする理由がありません。
    bindService(new Intent(MessengerServiceActivity.this, 
        MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
    mCallbackText.setText("Binding.");
  }
  
  void doUnbindService() {
    if (mIsBound) {
      // サービスを受信し、それゆえに登録している場合は、
      // ここでは、登録を解除する時間である。
      if (mService != null) {
        try {
          Message msg = Message.obtain(null,
              MessengerService.MSG_UNREGISTER_CLIENT);
          msg.replyTo = mMessenger;
          mService.send(msg);
        } catch (RemoteException e) {
          // There is nothing special we need to do if the service
          // has crashed.
        }
      }
      
      // Detach our existing connection.
      unbindService(mConnection);
      mIsBound = false;
      mCallbackText.setText("Unbinding.");
    }
  }
  
  /**
   * 標準的なこのアクティビティの初期化。UIをセットアップし、それから
   * 何かする前にユーザーがそれを突くのを待ちます。(?)
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    setContentView(R.layout.main);
    
    // ボタンのクリックを見張る
    Button button = (Button)findViewById(R.id.bind);
    button.setOnClickListener(mBindListener);
    button = (Button)findViewById(R.id.unbind);
    button.setOnClickListener(mUnbindListener);
    
    mCallbackText = (TextView)findViewById(R.id.callback);
    mCallbackText.setText("Not attached.");
  }
  
  private OnClickListener mBindListener = new OnClickListener() {
    public void onClick(View v) {
      doBindService();
    }
  };
  
  private OnClickListener mUnbindListener = new OnClickListener() {
    public void onClick(View v) {
      doUnbindService();
    }
  };
}

他のプロセスからバインドを許可する場合は、AndroidManifest.xml以下のようにintent-fileter要素を加える。
<service android:name=".MessengerService">
  <intent-filter>
    <action android:name="com.example.messengerserviceexample.MessengerService" />
  </intent-filter>
</service>

service要素にandroid:process属性を追加すると、サービスを別プロセスにできる。
android:process属性の値は、コロンで始まる値だとサービスのプロセスがアプリケーションでプライベートとなり、小文字で始まる場合(ドットで始まる場合も?)はグローバルプロセスになる。プライベートとかグローバルとかの意味はわからないが^^;

上記のサービスにバインドするアクティビティのコード。MessengerServiceActivityとほぼ同じ。bindService()の引数のIntentを作るときの引数を文字列にしている。クラスを渡したらなんかNoClassDefFoundErrorが起きた。
プロジェクトのプロパティのプロジェクト参照でMessengerServiceをチェックし、Javaのビルド・パスのプロジェクトタブでMessengerServiceを追加。
package com.example.messengerserviceclient;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.messengerserviceexample.MessengerService;

/**
 * 他のアプリからMessengerServiceにバインドするアクティビティ。
 * API Demoのコードほぼそのまま。
 * 元のコードはpublic static な入れ子クラスでAcitivityを実装していたが
 * 入れ子じゃない外側のクラスにした。
 */
public class MessengerServiceClient extends Activity {
  
  /** サービスと通信するためのメッセンジャー */
  Messenger mService = null;
  /** サービスにバインドを呼んだかを示すフラグ */
  boolean mIsBound;
  /** 状態を表示するためのテキストビュー */
  TextView mCallbackText;
  
  /**
   * サービスからやってくるメッセージのハンドラ
   */
  class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case MessengerService.MSG_SET_VALUE:
        mCallbackText.setText("Received from service: " + msg.arg1);
        break;
      default:
        super.handleMessage(msg);
      }
    }
  }
  
  /**
   * クライアントがIncomingHandlerにメッセージを送るターゲット、われわれが公開した(?)
   */
  final Messenger mMessenger = new Messenger(new IncomingHandler());
        
  /**
   * サービスのメインインタフェースと相互に作用するためのクラス
   */
  private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
        IBinder service) {
      
      mService = new Messenger(service);
      mCallbackText.setText("Attached.");

      // サービスと接続している限りサービスを監視したい
      try {
        Message msg = Message.obtain(null,
            MessengerService.MSG_REGISTER_CLIENT);
        msg.replyTo = mMessenger;
        mService.send(msg);
        
        // 例としてある値を与える
        msg = Message.obtain(null,
            MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
        mService.send(msg);
      } catch (RemoteException e) {
      }
      
      // サンプルの一環として、何が起きたかユーザーに表示する
      Toast.makeText(MessengerServiceClient.this, R.string.remote_service_connected,
          Toast.LENGTH_SHORT).show();
    }
    
    public void onServiceDisconnected(ComponentName className) {
      // これはサービスのコネクションが不意に切断された場合
      // -- すなわちプロセスがクラッシュした場合に呼ばれる。
      mService = null;
      mCallbackText.setText("Disconnected.");
      
      // サンプルの一環として、何が起きたかユーザーに表示する
      Toast.makeText(MessengerServiceClient.this, R.string.remote_service_disconnected,
          Toast.LENGTH_SHORT).show();
    }
  };
  
  void doBindService() {
    // サービスのコネクションを確立する。明示的なクラス名を使う。
    // なぜなら他のアプリケーションが私たちのコンポーネントを
    // 交換できるようにできるようにする理由がありません。
//    bindService(new Intent(MessengerServiceClient.this, 
//        com.example.messengerserviceexample.MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
    bindService(
        new Intent("com.example.messengerserviceexample.MessengerService"),
        mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
    mCallbackText.setText("Binding.");
  }
  
  void doUnbindService() {
    if (mIsBound) {
      // サービスを受信し、それゆえに登録している場合は、
      // ここでは、登録を解除する時間である。
      if (mService != null) {
        try {
          Message msg = Message.obtain(null,
              MessengerService.MSG_UNREGISTER_CLIENT);
          msg.replyTo = mMessenger;
          mService.send(msg);
        } catch (RemoteException e) {
          // There is nothing special we need to do if the service
          // has crashed.
        }
      }
      
      // Detach our existing connection.
      unbindService(mConnection);
      mIsBound = false;
      mCallbackText.setText("Unbinding.");
    }
  }
  
  /**
   * 標準的なこのアクティビティの初期化。UIをセットアップし、それから
   * 何かする前にユーザーがそれを突くのを待ちます。(?)
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    setContentView(R.layout.main);
    
    // ボタンのクリックを見張る
    Button button = (Button)findViewById(R.id.bind);
    button.setOnClickListener(mBindListener);
    button = (Button)findViewById(R.id.unbind);
    button.setOnClickListener(mUnbindListener);
    
    mCallbackText = (TextView)findViewById(R.id.callback);
    mCallbackText.setText("Not attached.");
  }
  
  private OnClickListener mBindListener = new OnClickListener() {
    public void onClick(View v) {
      doBindService();
    }
  };
  
  private OnClickListener mUnbindListener = new OnClickListener() {
    public void onClick(View v) {
      doUnbindService();
    }
  };
}

参考:
Android: MessengerでServiceとbindする << えふログ
Service - Messengerを使ったProcess間通信 - The blog :: Memo & Journal
サービスをアプリケーションプロセスから分離する - Kazzzの日記

Androidスマホの時刻合わせ

Xperia rayの時計がきっちりしていない。
設定>日付と時刻>自動にチェックを入れても時計が合わない。SIMカードを入れてないと無効らしい。
手動の時刻設定は分までしか設定できない。設定ボタンを押した瞬間に秒が0秒になるわけではないので秒単位での時刻設定は出来ない。
NTPで時刻合わせるアプリはあるが、root化してないと使えないらしい。
なんだかなあ。

NECのLifeTouch NOTEとかSIMカードスロットがないデバイスはどうするんだろう。専用の時刻合わせアプリケーションでも搭載しているのかな。

October 28, 2011

碧の軌跡をやった人の感想

伝説のままで…紺碧の軌跡 | スラッシュドット・ジャパン Journal


前作があまりにもがっかりなシナリオだったので今作はやるつもりないけど、もしやったら同じ感想だろうなあ。
#ベスト版とか中古屋で3000円切るようなら、やるかも。
「対象が40歳以上」ってのは納得。あ、もしかして1週回って小中学生には受け入れられてるのかなw

amazonのレビューは絶賛してるのが多いが、なかには冷静な感想もある。
「主人公の言動が場面によって一貫してない。」
とか
「なぜ主人公が惚れられるのかさっぱりわからない。」
など。。。

このシリーズはゲームシステムは良くできてると思うから、もうちょっとまともなシナリオライターを育てるなり連れてくるなりすればいいのに。
次回作は虚淵玄に頼めw

October 27, 2011

Androidアプリ開発メモ032:サービス その4:バインドされたサービス

サービスについての以前の記事:
Androidアプリ開発メモ021:サービス
Androidアプリ開発メモ030:サービス その2
Androidアプリ開発メモ031:サービス その3:IntentService

バインドされたサービスとは
バインドされたサービスとは、クライアントコンポーネントがそのサービスにバインドし、双方向なやり取りが可能なサービスである。サービスのonBind()コールバックメソッドはIBinderオブジェクトを返す。IBinderオブジェクトはクライアントコンポーネントにサービスへのプログラミングインタフェースを提供する。
クライアントコンポーネントはbindService()でサービスをバインドする。その際、引数にServiceConnectionインタフェースを実装しているインスタンスを渡す。
Androidアプリ開発メモ030:サービス その2の「サービスの種類」も参照。

IBinderの提示方法
以下の3つの方法がある。

Binderクラスの拡張
ローカルサービスでのみ使用できる方法。Binderクラスを拡張したクラスのオブジェクトをonBind()で返す。
この記事ではこの方法について説明する。
メッセンジャーの使用
リモートサービスでも使用できる。
AIDLの使用
AIDL(Android インターフェイス定義言語 : Android Interface Definition Language)を利用する。 #AIDLがどういうものかは調べていない^^; マルチスレッド化など複雑なことができるが実装も複雑になるらしい。

バインドされたサービスのライフサイクル
クライアントコンポーネントでContext#bindSerivice()が呼ばれると、サービス側ではonCreate()、onBind()がシステムに呼ばれる。サービスが既に存在する場合はonBind()だけが呼ばれる。
すべてのクライアントコンポーネントがアンバインドされるとonDestroy()がシステムに呼ばれてサービスは破棄される。アンバインドにはContext#unbindService()を使う。

実装
「Binderクラスの拡張」の方法では、以下のように実装する。

  1. サービスで、以下のいずれかのを行うBinderのインスタンスを作成する。
    • クライアントが呼び出せるpublicメソッドを含める。
    • クライアントが呼び出せるpublicメソッドを持つ、現在のServiceインスタンスを返す。
    • クライアントが呼び出せるpublicメソッドを持つサービスによりホストされた別のクラスのインスタンスを返す。
  2. サービスで、BinderのインスタンスをonBind()コールバックメソッドから返す。
  3. クライアントでBinderをonServiceConnected()コールバックメソッドから受け取り、提供されたメソッドを使ってバインドされたサービスを呼び出す。

android.app.Serviceクラス
public abstract IBinder onBind(Intent intent)
サービスへのコミュニケーションチャネルを返す。クライアントがサービスにバインドしてはならない場合はnullを返す。

android.content.Contextクラス
public abstract boolean bindService(Intent service, ServiceConnection conn, int flags)
サービスに接続する。必要ならばサービスを作成する。

android.content.Contextクラス
public abstract void unbindService(ServiceConnection conn)
サービスから切断する。

bindService()はServiceConnectionを引数に取るため、クライアントコンポーネントはServiceConnectionの実装を定義してそのインスタンスを作成する必要がある。ServiceConnectionインタフェースにはonServiceConnected()とonServiceDisconnected()の2つのメソッドがある。
クライアントコンポーネントとサービスが接続されるとシステムがonServiceConnected()を呼ぶ。
クライアントコンポーネントとサービスとの接続が予期せず失われた場合(サービスがクラッシュした場合、強制終了された場合など)にシステムがonServiceDisconnected()を呼ぶ。「予期せず接続が切れた場合」に呼ばれるのであって、unbind()で接続が切れる場合にはonServiceDisconnected()は呼ばれない。

android.content.ServiceConnectionインタフェース
public abstract void onServiceConnected (ComponentName name, IBinder service) 
サービスへの接続が確立したときに呼ばれる。

android.content.ServiceConnectionインタフェース
public abstract void onServiceDisconnected (ComponentName name) 
サービスへの接続が失われたときに呼ばれる。

ApiDemoの
com.example.android.apis.app.LocalServiceActivities の静的ネストクラスBinding
com.example.android.apis.app.LocalService(「開始された」サービスも一緒に書かれている)
が参考になる。
実際のアプリケーションではLocalServiceにこのサービスの機能をクライアントコンポーネントに利用させるためのpublicメソッドを用意する。
ApiDemoの"App/Service/Local Service Binding"で「Bindign Service」ボタンを押下するとサービスが開始され、「Unbind Service」ボタンを押下するとサービスが終了する。
また、Backキーでもサービスは終了する。サービスをバインドしていたアクティビティがスタックの先頭からポップされて破棄されるので、サービスはアンバインドされて終了するのだと思う。

参考サイト:
AndroidのServiceについて - adsaria mood

batファイルを常に管理者権限で実行する

Windows7でアプリケーションを常に管理者権限で実行するには、ファイルのプロパティを開いて「特権レベル」タブの下の方にある「管理者としてこのプログラムを実行する」にチェックを入れればよい。
しかし、batファイルの場合、上記のチェックボックスがdisableになっていてこの方法が使えない。
#そういうものなのか、それともウイルスバスターとかセキュリティ系のアプリケーションがそういう風にWindows7の設定を変えているのか。

batファイルを管理者権限で実行するには、タスクスケジューラを使えばよい。
タスクスケジューラは「コントロールパネル>システムとセキュリティ>管理ツール」にある。
1.batファイルを実行するタスクを作成する。
2.タスクのプロパティで「最上位の特権で実行する」にチェックを入れる。
3.タスクを実行するバッチファイルを作る。

「バッチファイルを動かすタスクを動かすバッチファイル」ってなんかアレだが、一応この方法で毎回管理者権限で実行できる。

参考:
「管理者権限で実行」を選ばなくても、最初から管理者権限で実行させたいの - Windows 7 - 教えて!goo
タスク・スケジューラの基本的な使い方(Windows 7/Windows Server 2008 R2編) - @IT
SchTasks.exe を使用してタスクを作成して管理する

October 25, 2011

求職活動開始

求職活動を開始した。
転職活動ではない。
ブログには書いてなかったが、今年の5月、退職した。
もっと言うなら、それよりずっと前から休職していた。あと1ヶ月弱で丸2年働いてないことになる。

そろそろ働かないといろいろマズイと思い動き始めたのだが、丸2年生きてるんだか死んでるんだかわからないような状態だった人間を雇ってくれるところがあるだろうか。
前の求職活動の時、「1年ブランクがあるから」と断られたことが何度もあった。
それが、今度は2年のブランクだ。年齢も四捨五入すれば40になるし。

とりあえず、とある会社に「求人ありますか?」とメールしてみた。
しかし、送ったメールをよく読んでみたら、自分の年齢を間違えていたw

はてさて、どうなることやら。

ココログとtwitterの連携機能を有効にした

ココログには公式にtwitterとの連携機能があるというのを今日知ったw クロスポストしてくれるらしい。
早速、その機能を有効にしてみた。
この記事以降、ココログに投稿すると自動的にtwitterにも投稿されるようになった。
なってるはず^^;

October 24, 2011

Androidアプリ開発メモ031:サービス その3:IntentService

サービスについての以前の記事:
Androidアプリ開発メモ021:サービス
Androidアプリ開発メモ030:サービス その2

IntentService
IntentServiceクラスはSerivceクラスのサブクラスで、非同期・バックグラウンドで実行する処理を実装するのに使えるクラス。
リファレンスには

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand.
IntentServiceは、サービスのためのベースクラスである。オンデマンドで非同期要求(Intentで表現された)をハンドルする。
とある。
IntentService は以下のことをしてくれる。
  • アプリケーションのメインスレッドから分離したデフォルトのワーカスレッドを作成し、onStartCommand()に配信されるすべてのインテントを実行する。
  • onHandleIntent()の実装にひとつのインテントを渡すワークキューを作成することにより、マルチスレッドに関する心配はなくなる。
  • 開始要求のすべてをハンドルした後、サービスを停止することにより、stopSelf()を呼び出す必要はなくなる。
  • null を返すonBind()のデフォルト実装を提供する。
  • ワークキュー、その後onHandleIntent()の実装にインテントを送信するonStartCommand()のデフォルト実装を提供する。
Serviceクラスを継承してサービスを実装し別スレッドを作った場合、stopService()を呼ぶと別スレッドも終わってしまうが、IntentServiceを継承した場合は別スレッドは何事もなく続く。
参考サイト2に載っている「Serviceの起動停止のサンプル」はServiceを継承したもので、IntentServiceを利用したサービスのサンプルはIntentServiceを継承している。
前者はstopService()の呼び出しでWorkerThreadではInterruputedExceptionが発生してWorkerThreadも終了するが、後者ではstopService()が呼ばれても別スレッドは実行が継続される。
なぜ前者においてstopService()でWorkerThreadに例外が発生するのかがわからないが、動作としては上記のような違いが出る。
このような違いがあるので、サービスが止まったとしても別スレッドで処理が終了するまで実行しっ放しの実装にIntentServiceを使うことができる。

EclipseでIntentServiceを継承したクラスを作成するとクイックフィックスにString型の引数を取るコンストラクタが出てくるが、実際に必要なのは引数なしのコンストラクタなので注意が必要。
String型の引数を取るコンストラクタで実行した場合、サービスを開始しようとすると実行時エラーが出る。
onStartCommand(),onCreate(),onDestroy()などのコールバックメソッドをオーバーライドする場合は、必ずsuperの実装を呼び出すようにする必要がある。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  // 何か処理をする
  return super.onStartCommand(Intent intent, int flags, int startId);
}

ログを出すだけのサンプルコード。連続してstartService()を呼んでも1つずつ順番に実行される。
package com.example.intentserviceexample;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

/**
 * IntentServiceを継承したクラス
 */
public class MyService extends IntentService {

  public MyService() {
    super("MyService");
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    try {
      int thNo = intent.getIntExtra("th_no", -1);
      Log.v("IntentService", thNo + ":start thread");
      Thread.sleep(5000);
      Log.v("IntentService", thNo + ":end thread");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

参考サイト:
1.2. サービス - ソフトウェア技術ドキュメントを勝手に翻訳
2.Android | ナレッジデザイン大竹のホームページ (by drupal)
3.IntentService - Boring Days in tech
4.IntentServiceを使って非同期処理を行う<< Tech Booster

October 23, 2011

Androidアプリ開発メモ030:サービス その2

前のサービスに関する記事は後から読んでもぜんぜんわからないので、あらためサービスについて末尾に書いた参考サイトを読んで、自分なりにまとめてみた。

サービスとは

サービスはユーザインタフェースを持たずバックグラウンドで動作するコンポーネント。
サービスは標準ではホストプロセスのメインスレッドで実行される。別スレッドでも別プロセスでもない。サービスで重い処理をして他の操作をブロックしてしまう可能性があれば、サービス内で別スレッドを生成してそちらで処理をさせる方がいい。

サービスを使う場面

たとえばタイマーのアプリを考えると、アクティビティで別スレッドを生成して一定時間後に音が鳴るようにした場合、スレッドを生成したアクティビティ(メインスレッド)が終了すると、別スレッドを変更できないのでタイマーを中止したり設定を変更したりできない。
サービスを使えば、後からタイマーの中止・変更が可能。

サービスの種類

サービスは2つの形態を取る。両方の形態を兼ね備える場合もある。

開始された(Started)
アプリケーションコンポーネント ( アクティビティなど ) が startService() を呼び出してサービスを開始したとき、サービスが "開始された" 状態になる。startService()の引数のIntentでどのサービスを開始するか指定する。
サービスを開始したコンポーネントが終了しても、サービスはバックグラウンドで動く。
サービスは開始したコンポーネントに何か返したりしない。
サービスは処理が終わったら自身で stopSelf() または stopSelfResult() を呼ぶか、他のコンポーネントがContext#stopService()を呼ぶかして終了しなければならない。
バインドされた(bound)
アプリケーションコンポーネントが bindService() を呼び出してサービスにバインドしたとき、サービスが "バインドされた" 状態になる。
バインドされたサービスは、コンポーネントとサービスとのやり取りのためのインターフェイスを提供する。
複数のコンポーネントがサービスにバインドすることができる。すべてのコンポーネントがアンバインドされるとそのサービスは、(startService()で開始されていないならば)破棄される。
また、サービスがクライアントコンポーネントと同じプロセスで動く場合はをローカルサービス、異なるプロセスで動く場合をリモートサービスという。

「開始された」サービスのライフサイクル

startService()でサービスが開始されると、サービスのonCreate(),onStartCommand()がシステムに呼ばれる。サービスがすでに存在する場合はonStartCommand()だけが呼ばれる。
stopService()が実行された場合またはサービス自身がstopSelf()を呼んだ場合、onDestroy()がシステムに呼ばれる。

参考:Intent起動のServiceのライフサイクル <<えふログ

onStartCommand()の戻り値は下記の定数を使わなければならない。どれを返すかによりonStartCommand()から戻った後でシステムがサービスを強制終了した場合の動作が変わる。

START_NOT_STICKTY 配信されるペンディングインテントが存在しない限りサービスは再作成されない。
START_STICKY サービスを再作成し、onStartCommand() を呼び出すが、最後のインテントは再配信さない。その代わり、サービスを開始するペンディングインテントがない場合はシステムがインテントをnullにしてonStartCommand() 呼び出す。
START_REDELIVER_INTENT サービスを作成し、最後にサービスに配信された最後のインテントで onStartCommand() を呼び出す。
START_STICKY_COMPATIBILITY この定数の説明には「強制終了された後にonStartCommand()が呼ばれることは保障されない。」とある。またonStartCommand()の引数intentの説明に「以前にSTART_STICKY_COMPATIBILITY以外のものが返された場合、これはnullになることがある。」とある。よって、onStartCommand()がSTART_STICKY_COMPATIBILITYを返した後にシステムがサービスを強制終了すると、intentがあればonStartCommand()を呼び出すが、intentがなければonStartCommand()は呼ばれないものと思われる(呼ばれた場合はintentはnullではない)。
START_STICKYを返した場合は、onStartCommand()でintentがnullになっている場合がある。
START_STICKY_COMPATIBILITYを返しておくのが無難?

サンプルコード

ApiDemoの
com.example.android.apis.app.LocalServiceActivities.java の静的ネストクラスController
com.example.android.apis.app.LocalService.java(バインドされたサービスも一緒に書かれている)

単純なサービス - Android 開発入門

繰り返し処理を行うとき - Android 開発入門

mp3を再生するサンプルアプリ。
サービスを利用するアクティビティのコード。

package com.example.localserviceexample;

import java.util.List;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class LocalServiceExample extends Activity 
  implements View.OnClickListener {
  
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // ボタンの設定
    Button startButton  = (Button)findViewById(R.id.startButton);
    startButton.setOnClickListener(this);
    Button stopButton  = (Button)findViewById(R.id.stopButton);
    stopButton.setOnClickListener(this);
  }
  
  /**
   * ボタン押下時の処理
   */
  @Override
  public void onClick(View v) {
    String tag = (String)v.getTag();
    if (tag.equals("start")) {
      if (isServiceRunning("com.example.serviceex.PlayerService")) {
        return;
      }
      
      // プレイヤーサービスの開始
      Intent intent = new Intent(this, com.example.localserviceexample.PlayerService.class);
      startService(intent);
      
    } else if (tag.equals("stop")) {
      // プレイヤーサービスの停止
      Intent intent = new Intent(this, com.example.localserviceexample.PlayerService.class);
      stopService(intent);
    }
  }
    
  /**
   * サービス起動中かどうかを返す。
   * @param className
   * @return
   */
  private boolean isServiceRunning(String className) {
    ActivityManager am
      = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
    List serviceInfos
      = am.getRunningServices(Integer.MAX_VALUE);
    for (int i = 0; i < serviceInfos.size(); i++) {
      if (serviceInfos.get(i).service.getClassName().equals(className)) {
        return true;
      }
    }
    return false;
  }
}

サービスのコード。
package com.example.localserviceexample;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import android.media.MediaPlayer;

public class PlayerService extends Service
  implements MediaPlayer.OnCompletionListener {
  
  private static final int NOTIFICATION_ID = 0;

  private MediaPlayer mediaPlayer;
  private NotificationManager notificationManager;

  @Override
  public void onCreate() {
    super.onCreate();
    Log.v("SERVICE", "onCreate");
    
    notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
      Log.v("SERVICE", "onStartCommand");
    
    // ノーティフィケーションの表示
    showNotification(
        this, R.drawable.icon,
        "サウンドを再生します。",
        "プレイヤーサービス",
        "プレイヤーサービスを開始しました。");
    
    // サウンドの再生
    playSound();
    
    return Service.START_STICKY_COMPATIBILITY;
  }

  @Override
  public void onDestroy() {
      Log.v("SERVICE", "onDestroy");
      
    // ノーティフィケーションの取り消し
    notificationManager.cancel(NOTIFICATION_ID);
    
    // サウンド再生の停止
    stopSound();
    
    // トーストの表示
    Toast.makeText(
        this,
        "プレイヤーサービスを停止しました。",
        Toast.LENGTH_LONG).show();
  }

  @Override
  public void onCompletion(MediaPlayer mp) {
      Log.v("SERVICE", "onCompletion");
    stopSound();
  }

  @Override
  public IBinder onBind(Intent arg0) {
    return null;
  }

  /**
   * サウンドを生成する。
   */
  private void playSound() {
    try {
      if (mediaPlayer == null) {
        mediaPlayer = MediaPlayer.create(this, R.raw.sample);
        mediaPlayer.start();
        mediaPlayer.setOnCompletionListener(this);
      }
    } catch (IllegalStateException e) {
      e.printStackTrace();
    }
  }

  /**
   * サウンドを停止する。
   */
  private void stopSound() {
    try {
      if (mediaPlayer != null) {
        mediaPlayer.stop();
        mediaPlayer.setOnCompletionListener(null);
        mediaPlayer.release();
        mediaPlayer = null;
      }
    } catch (IllegalStateException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * ノーティフィケーションを表示する。
   */
  private  void showNotification(
      Context context, int icon, String tickerText,
      String contentTitle, String contentText) {
    
    // ノーティフィケーションの生成
    Notification notification
      = new Notification(icon, tickerText, System.currentTimeMillis());
    PendingIntent pendingIntent
      = PendingIntent.getActivity(
          context, 0,
          new Intent(context, com.example.localserviceexample.LocalServiceExample.class),
          0);
    notification.setLatestEventInfo(context, contentTitle, contentText, pendingIntent);
    
    // ノーティフィケーションの表示
    notificationManager.notify(NOTIFICATION_ID, notification);
  }
}

AndroidManifest.xmlにはapplication要素の子要素として(activity要素と同じレベル)、service要素を追加する。
<service android:name=".PlayerService" />

参考:
2. サービス - ソフトウェア技術ドキュメントを勝手に翻訳
サービス - Android 開発入門
AndroidのServiceについて - adsaria mood
Android: Serviceのノウハウ << えふログ

第30節、新潟は福岡に引導を渡す、磐田は知らん

J's GOAL:試合詳細:2011 J1 第30節 アルビレックス新潟 3-1 アビスパ福岡

Dsc_0001

初めて恵比寿のFootnikで観戦。
#大崎のは行った事がある。
前半、あっという間に勲の先制ゴール!!
その後2点を追加し、反撃を1点に抑えて勝利!!
土壇場に来て3連勝で勝ち点38。過去、この勝点で入れ替え戦行き・降格したチームはない。
甲府が負けたので16位との勝ち点差は8。得失点差も考えると降格の可能性はかなり小さくなったと言えるだろう。
よかった~。

この試合も3得点。攻撃陣の外人は好調だ。ヨンチョル2得点。ミシェウ、ブルロペも好調。
ただ、他がなあ。悪くはないが得点に結びついていない。
高さがないことはないと思うのだが、CK・FKからの得点が少ない。アトムはプレイスキックのキッカーとして、マルシオはもちろん松下にも及ばない気がする。
次節はミシェウが出場停止、優勝争い中のチームが相手で厳しい戦いが続くが、勝点を少しでも積み上げで残留を確実なものにしたい。
ここからACL圏内や賞金圏内に行くのは無理なのが悲しいが、一桁順位になればうれしいな。


J's GOAL:試合詳細:2011 J1 第30節 ジュビロ磐田 0-4 セレッソ大阪


まだスポーツニュース見てないけど、なにやってんの。
はぁ。


恵比寿Footnikまでチャリで行ったが、あらためて東京の起伏を感じた。坂道多い^^;
Footnikはスカパー見れるのはいいんだけど、メニューがもうちょっとなあ。ランチタイムじゃないし店員も少ないから仕方ないのかもしれないが、もう少しメシっぽいもの(サンドイッチとかハンバーガーとか)を出してくれないもんだろうか。
あと、客がみんなおとなしい。人のこと言えないが^^;
カップルや仲間で来ている人もいるが、俺のようなさびしい男のソロ観戦も結構多い感じ。
点入った時に知らない隣の人とハイタッチとかすればいいのに。無理か^^;

大阪ダブル選挙

asahi.com(朝日新聞社):橋下知事が辞職を申し出 ダブル選日程は22日中に確定 - 関西ニュース一般

橋本大阪府知事が辞表を出して大阪の府知事選・市長選のダブル選挙が確定した。
大阪には特に縁はないが、大きく報道されているのでちょっと考えてみた。
橋本知事は「大阪都構想」を標榜し、平松市長は反対している。

橋本知事の「今の大阪府と大阪市が並び立つ状態では誰が知事・市長になっても二重行政の問題は解決しない。」という意見は説得力がある。
ただ、大阪都構想に必要な法改正ができるのか。実現へのはっきりとした見通しは立ってないように思う。

平松市長が大阪市の職員達に取り込まれたように見えるなあ。
橋本知事が就任した当初、平松市長も二重行政の解消に積極的に見えた。しかし実際に水道局の合併の交渉が始まると大阪市側の人が大阪府を恫喝するようなこと言ったりして頓挫。平松市長はそれを止めるでもなく放置。
「大阪市をつぶすな」というが、ここで言っている「大阪市」は「大阪市民」ではなくて「大阪市の職員」だろう。実際、平松市長を応援する会とかって大阪市職員OBとかが大量に動員をかけているというし。
大阪都構想に対して平松市長は広域行政のための協議会を作るといっているが、そんな協議会如きで二重行政がなくなるなら誰も苦労しない。協議会が発足しても議論のための議論ばかりで何も進まないだろう。
それどころか「協議会のために事務局が必要です。」とか言ってまた無駄な金がかかるだけになりそう。

今のところ橋本知事の方がまともなことを言っているように思う。
ただ橋本知事にもどうかと思うところがある。敵を激しく口撃したりするところとか、教育改革とか。
全般的に「競争原理を導入すればなんでもうまくいく。」と信じているように思う。自分の能力が高い人が陥りがちな考えだよな。
小泉政権以降、「すべて自己責任、自由競争」っていう風に世の中がなっていって、よくなったこともあるけど弊害も相当出た。自由化すればいいってものでもないと思うが。
学校の先生に評価制度の導入は反対だ。何をもって評価するの?進学実績?
先生の能力なんてそんな数字で測れるものじゃないし、そもそも校長や教頭が先生を公正に評価なんてできるのか疑問。
それにただでさえ直接教育と関係ないような事務仕事やらレポート作成やらで忙しい先生たちに、さらに目標設定だの自己評価レポートだの作成をさせて負担を強いるなんて、絶対に良い結果にならないと思うのだが。
大阪の学力テストの結果が低いのを日教組と教師の怠慢のせいだけにして、そもそも学力の低さは学校と教師だけが原因なのか?家庭のことを考えなくてもいいのか?
いくら学校で一生懸命勉強教えようとしても、学ぼうとしないやつは学ばないし、学校で授業受けても家庭学習をしなければ学力は上がらないと思うのだが。


まあ、おいらには府知事選にも市長選にも投票権はないので考えるだけ無駄なのだが^^;

October 22, 2011

FF11 クエレブレ召ソロでタロンギのクエスト完了

先日タロンギのクエ「道を切り開け!」をクリアしたので、残るクエは「無へ誘う使者」のみとなった。
倒すNMはやっかいな状態異常がないCuelebre(クエレブレ)がいいかなと思い、シーフで行ってみた。しかし全く攻撃が当たらない。返り討ちになった。
ネットで調べたら、このウィルムNMは飛行したままで近接攻撃が当たらないそうだorz

敵の攻撃は土属性でガルーダなら沈まないらしいので、召ソロで再挑戦。
確かにガルーダは通常攻撃で15前後しかダメージ受けない。「風の囁き」で回復していれば沈まない。
が、こちらの攻撃はウインドブレードだけ。なかなか削れない。
NMのヒットポイントが減ってくるとオーカーブラストを使ってくる。これは結構痛い。
ガルーダは大丈夫だがきちんと回復しないと本体が死にそう^^;
あと後半はブレクガを2回使ってきた。1回目はレジストしたが、2回目は石化。しかし、思ったより早く回復したのでしのぐことができた。ハーフレジストしたのかな。
30分以上かけ、ダスティエーテル1、2、ダスティエリクサー、あとなんとかエリクサーも使っててなんとか勝った。

拠点に戻って報告し、タロンギのクエをコンプリート。
大した報酬はないのだが、なんかうれしい^^


クエレブレ戦についてのメモ。
・ウインドブレードはかなりハーフレジストされた。風曜日にやった方が良さそう。
・アートマは邪気と野望を使ったがそれでもMPは足りなくなった。サポは赤の方がいいかも。リフレがあるし、敵のストンスキンをディスペルで消せるかもしれない。自分にはストンスキンを常にかけておき、回復にはリジェネ2をなるべく使ってMPの節約に努めるといいだろう。
・気休めかもしれないが、後半になったらブレクガによる石化の時間が短くなることに期待してバストンしておいた方がいい。

FF11 アットワスラッグNM赤ソロ

昨日、アットワのスラッグNMに赤ソロでやってみた。
今まで召でラムウ出して何度か挑んでたが、負け続けていた。召喚獣が沈むと再召還しても本体にタゲがひっついてしまう。
忍/踊で勝っている人を見たので自分はシ/踊でやってみようかと思ったが、ネットで調べたら赤ソロでマラソンして13分で勝ったというのがあったので、赤でやってみた。

赤/白で竜巻下衣と野望の人工アートマを付け、移動力を強化して戦闘開始。
やってみるととても13分では倒せなかった。30分以上かかったような気がする。
でもグラビデが確実に入るのでマラソンは簡単。ウォタガやウォタジャは詠唱し始めたら逃げれば避けられる。
とにかく時間がかかるが、負けることはないと思った。

ドロップはカリス頭1個。忍が欲しかったので、残念。

October 21, 2011

b-mobileのtalking SIMだけでいけるか

Xperia rayは未だSIMカードなしの状態で運用している。
PHSを解約してb-mobileの「音声+データ」のSIMカードを挿したXperia rayだけにすることが可能かどうか考えてみた。

おいらのXperia rayはFOMAプラスエリアでは使えないが、それでもPHSよりは使えるところが増えるだろう。
特に釣りに行ったときとか。

b-mobileだとメールアドレスがもらえないのが難点。
家でXperia rayのWiFiをON、Gmailの同期を有効にしてGmail宛にメールを送ってみると、数分でメールが通知された。
携帯キャリアのメールなくてもGmailでなんとかなりそう。

b-mobile導入するなら、どのサービスにするかが悩むところ。
talking 1GB定額1GBまでor30日間で3480円。
talking Fair は1GBまでor120日間で9800円。120日間保ったとすれば約2500円/月。
talking sim は定額だけど最大300Kbpsで3960円。
普通に使って月何バイトくらいになるかわからないからなあ。

とりあえずデータ通信のみのSIMを買ってみて、どれくらいデータ通信するのか確認してからどの通話付きサービスにするか決めよう。

October 19, 2011

Androidアプリ開発メモ029:モーションセンサー その3 SensorManager#getOrientation()

前のセンサの記事で方位と傾きの取得する方法として
・getDefaultSensor()やgetSensorlist()でタイプをSensor.TYPE_ORIENTATIONに指定してセンサを取得する
やり方を説明したが、これは現在は推奨されていない。
現在推奨されているのはgetOrientation()を使用する方法である。

しかし、リファレンス読んでもおいらの頭では理解不能^^;
線形代数学の授業、全く理解できなかったからなあorz
3Dグラフィックスやっている人には分かるのかな。
#この方法だとOpen GLとか3Dライブラリと親和性が高いとどこかに書いてあった。
で、自分には意味不明なので、

「お約束としてSensorManagerの3つのstaticメソッドgetRotationMatrix()、remapCoordinateSystem()、getOrientation()をこの順番で呼ぶ」

と覚えることにした。バカ丸出しだ。

remapCoordinateSystem()の第2、第3引数は、デバイスのX軸、Y軸がそれぞれ指している世界座標系の方向を指定する。
例:
画面が縦長表示(portrait)でデバイスを水平に持ってディスプレイを真上に向けた場合は

remapCoordinateSystem(inR, AXIS_X, AXIS_Y, outR); 
デバイスを縦に持って背面カメラを正面に向けディスプレイを持っている人に向けた状態の場合は
remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR); 
画面が横長表示(landscape)でデバイスを水平に持ってディスプレイを真上に向けた場合は
remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR); 

getOrientation()で取得した方位・傾きはラジアンで、反時計回りで正の値。
ラジアンはMath#toDegrees()で度に変換できる。
「反時計回りで正」っていうのも良く分からない。デバイスを縦に持って左(反時計回り)に傾けたらロールが負の値になった。Y軸の正の方から原点方向を見た場合に反時計回りに回ると正ってことか?

怪しいサンプルプログラム

package com.example.orientationexample;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class OrientationExample extends Activity
  implements SensorEventListener {
  
  private TextView textView;
  
  private SensorManager sensorManager;
  private List accelerometers;  // 加速度センサー
  private List magnetics;  // 磁気センサー
  
  float[] aValues;    // 加速度センサの値
  float[] mValues;    // 磁気センサの値
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    textView = (TextView)findViewById(R.id.textView1);
    
    // センサーマネージャの取得
    sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
    
    // センサーの取得
    accelerometers = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
    magnetics = sensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
    
    Log.v("SENSOR", "num of accs:" + accelerometers == null ? "null": Integer.toString(accelerometers.size()));
    Log.v("SENSOR", "num of mags:" + magnetics == null ? "null": Integer.toString(magnetics.size()));
    }

  @Override
  protected void onResume() {
    super.onResume();
    
    // リスナの登録
    if (accelerometers != null) {
      for (Sensor accelerometer: accelerometers) {
        sensorManager.registerListener(
            this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
      }
    }
    if (magnetics != null) {
      for (Sensor magnetic: magnetics) {
        sensorManager.registerListener(
            this, magnetic, SensorManager.SENSOR_DELAY_NORMAL);
      }
    }
  }

  @Override
  protected void onPause() {
    super.onPause();
    
    // リスナの登録解除
    if (accelerometers != null) {
      for (Sensor accelerometer: accelerometers) {
        sensorManager.unregisterListener(this, accelerometer);
      }
    }
    if (magnetics != null) {
      for (Sensor magnetic: magnetics) {
        sensorManager.unregisterListener(this, magnetic);
      }
    }
  }

  @Override
  public void onSensorChanged(SensorEvent event) {
    float[] oValues = new float[3];    // 向き
    
    switch (event.sensor.getType()) {
    case Sensor.TYPE_ACCELEROMETER:
      aValues = event.values.clone();
      break;
    case Sensor.TYPE_MAGNETIC_FIELD:
      mValues = event.values.clone();
      break;
    default:
      Log.v("SENSOR", "unexpected type");
    }
    
    float[] R = new float[16];
    float[] I = new float[16];
    float[] outR = new float[16];
    
//    Log.v("SENSOR", "aValues=" + ((aValues != null) ? "not null" : "null") + " mValues=" + ((mValues != null) ? "not null" : "null"));
    if (aValues != null && mValues != null) {
      SensorManager.getRotationMatrix(R, I, aValues, mValues);
      SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Y, outR);	// デバイスを地面と水平にして縦長表示の場合
      SensorManager.getOrientation(outR, oValues);

      String text = "OrientationExample X Y"
        + "\n方位:"       + (int)Math.toDegrees(oValues[0])
        + "\nピッチ:"     + (int)Math.toDegrees(oValues[1])
        + "\nロール:"     + (int)Math.toDegrees(oValues[2]);
      textView.setText(text);
      aValues = null;
      mValues = null;
    }
  }
  
  @Override
  public void onAccuracyChanged(Sensor arg0, int arg1) {
  }
}

以下、3つメソッドのリファレンスの怪しい訳。

public static boolean getRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)
傾斜マトリックスIおよびベクトルをデバイス座標系から直接の正規直交基底として定義されている世界座標系に変換する回転マトリックスRを計算する。
・Xはベクトル積YZ(これはデバイスの現在の位置で地面に接しほぼ東を指している)として定義されている。
・Yはデバイスの現在の位置で地面に接し、磁北極の方向を指している。
・Zは空の向きを指し地面に対して垂直である。

定義により:
[0 0 g] = R * gravity (g = magnitude of gravity) 
[0 m 0] = I * R * geomagnetic (m = magnitude of geomagnetic field) 

デバイスが世界座標系にそろえられている場合、Rは単位行列(恒等行列?)である。すなわち、デバイスのX座標が東を指している場合、Y座標が北極を指していてデバイスは空に面している。

Iは重力(世界座標空間)と同じ座標空間に地磁気ベクトルを変換する回転行列である。IはX軸周りの単純な回転である。ラジアン単位の傾斜角度はgetInclination(float[])で計算することができる。

-------------------------
(訳すの面倒くさくなったので中略)
-------------------------
各行列の逆行列はその転置を取ることによって簡単に計算することができます。

この関数によって返される行列は、デバイスが自由落下ではなく磁北に近くない場合にのみ意味がある。装置が加速される、または強力な磁場に置かれている場合、返される行列が不正確になることがある。

引数
  R:この関数が帰った場合、回転行列Rを保持している浮動小数点数9個のarray。Rはnullもありうる。
  I:この関数が帰った場合、回転行列Iを保持している浮動小数点数9個のarray。Iはnullもありうる。
  gravity:デバイス座標で表される重力のベクトルを含む浮動小数点数3個のarray。単純にTYPE_ACCELEROMETERタイプのSensorのSensorEventによって返される値を使うことができる。
  geomagnetic:デバイス座標で表される地磁気のベクトルを含む浮動小数点数3個のarray。単純にTYPE_MAGNETIC_FIELDタイプのSensorのSensorEventによって返される値を使うことができる。
戻り値
  成功の場合はtrue。失敗の場合はfalse(たとえば、デバイスが自由落下している)。失敗の場際、出力行列は変更されない。


public static boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR)
与えられた回転行列を異なる座標系で表現されるように回転する。アプリケーションが異なる座標系にあるデバイスの三方向の角度を計算する必要があるときにこれは通常使用される(getOrientation(float[], float[])参照)。
もし画面が物理的に回転しなければ、回転行列が描画(たとえばOpenGL ESで)のために使用される場合、普通はこの関数で変換することは必要ではない。その場合、現在の画面の回転を取得するためにDisplay.getRotation()を使用できる。ユーザーは一般的に画面を回転させるのは自由なので、ここで利用するパラメータを決定するには回転を頻繁に考慮しなければならないことに注意してください。

例:
・回転角度が必要とされる拡張現実アプリケーションのためにカメラ(カメラの軸に沿ったY軸)を使う場合
    remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);
・回転がSurface.ROTATION_90のときにデバイスを機械式のコンパスとして使う場合
    remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR); 

上記の例では注意をせよ。この呼び出しは、回転角度を計算するときに、その自然の方向からの回転を計上するためにのみ必要です。回転行列がレンダリングのために使用されている場合も、変形は必要ない可能性もある、たとえばアクティビティがlandscapeモードで走っている場合。

結果として得られる座標系は正規直交であるので、二つの軸だけを指定する必要があります。

引数:
  inR:変換される回転行列。普通、それはgetRotationMatrix(float[], float[], float[], float[])によって返される。
  X:デバイスのX軸がマッピングされる世界の軸と方向を定義する。
  Y:デバイスのY軸がマッピングされる世界の軸と方向を定義する。
  outR:変換された回転行列。inRとoutRは同じarrayかもしれない。しかしそれは性能の理由から推奨されない。
戻り値:
  成功の場合true。入力パラメータが間違っている場合false。たとえばX軸とY軸が同じ軸の場合。あるいはinRとoutRが同じ長さではない場合。


public static float[] getOrientation(float[] R, float[] values)
回転行列に基づいてデバイスの向きを計算する。
返る場合、array valuesは次の結果が入れられる。:
・values[0]:アジマス。Z軸まわりの回転。
・values[1]:ピッチ。X軸まわりの回転。
・values[2]:ロール。Y軸周りの回転。
使用されるリファレンス座標系は回転行列に対して定義された世界座標系とは異なる。
・Xはベクトル積YZ(これはデバイスの現在の位置で地面に接しほぼ西を指している)として定義されている。
・Yはデバイスの現在の位置で地面に接し磁北極の方向を指している。
・Zは地球の中心法方向を指しており地面に対して垂直である。
上記すべて3つの角度はラジアン単位で反時計回り方向に正である。

引数
  R:回転行列。getRotationMatrix(float[], float[], float[], float[])参照。
  valuse:結果を保持する3個の浮動小数点数のarray
戻り値
  引き数として渡されたarray values。

October 18, 2011

結局プログラマを酷使してるだけじゃん

4Gamer.net ― [SQEXOC]プロジェクトを失敗させないためには? スクウェア・エニックスで実施されているプロジェクト管理術公開


「対処5:労働時間を180時間->290時間」
だってw
末端の作業者を深夜残業・休日出勤させてボロ雑巾のように酷使して完成させ、評価されるのは上にいるプロデューサーだけってことでしょ。
これのどこが「マネジメント」なんですかね。
潰れてしまえ□e!!

FF11 ORパンタロン+2をゲット

昨日のこと、
「SobekとCarabosseとBriareusを各1戦」
というシャウトがあったので、金行絵札希望で参加。

構成はシ、青/赤、黒/詩、白/黒。おいらは白。

Sobekは4人で大丈夫かなと思ったが、全く問題なし。
白のパライズがほぼ全部入って、たまに麻痺する。
LV95の威力か。
弱点突いて、金行の絵札をゲット。

CarabosseもBriareusも余裕。
トリガは全部そろっていて戦うだけだったので意外と早く終了。

金行の絵札は5枚持っていたので今回の1枚で6枚揃った。
庭に行って、ORパンタロン+2をゲット^^

ORパンタロン+2 防41 MND+7 回復魔法の詠唱時間-12% ケアル回復量の5%をMPに変換 ディバインベニゾン+1 白 Lv83

Androidアプリ開発メモ028:開発中のアプリのスクリーンショットの取り方

デバイスとPCをUSBで接続してデバイス上でデバッグを実行し、Eclipseで"Device"ビューを表示して右上のカメラのアイコンをクリックすると、スクリーンショット取得用のウィンドウが出てくる。

October 16, 2011

第29節、磐田は大丈夫だってw、新潟アウェイ川崎戦で初勝利

J's GOAL:試合詳細:2011 J1 第29節 ジュビロ磐田 1-2 鹿島アントラーズ

山本しゅうとのSBはもう無理だ。しゅうとを重用し続けるヤンツーは本当に今シーズン限りにしてくれ。

金園が10得点目。新人で2桁得点は城、渡邉千真に続き3人目。でもスポーツニュースでの扱いは小さい^^;

ブログで「もう1勝もできない、降格だ。」とネガってる人がいたが、それはないよ。
レッズと勝点差が9もある。得失点差も大きくプラスになっている。
またしてもホームで鹿島に負けて落ち込むのはわかるが、さすがにネガり過ぎだろう。

J's GOAL:試合詳細:2011 J1 第29節 川崎フロンターレ 1-2 アルビレックス新潟

等々力に出撃しようかとも思ったが、BS1の生中継があったので自宅観戦。
はー、勝って良かった。やっぱり俺が行くと負けるな。行かなくて良かったw

前半、川崎が決定的なチャンスを外してくれたが、こっちもミシュウさんがPK外すorz
後半、カウンターからブルロペが2得点^^
しかし菊地が不用意なことして2枚目のイエローで退場(-_-#)
ジュニーニョに1点返されたが、長~いロスタイムをなんとか守りきり、アウェイの川崎戦で初勝利^^
ロスタイムのドキドキは心臓に悪い^^;
#なんでロスタイムあんなに長いのさ。主審おかしいよ。

得点はブルロペ・ミシェウのコンビの見事なカウンターだったが、逆に他の選手が絡んだところから得点は生まれなかった。最後のところでプレーの精度が低い。
後半、カウンターで川又が持ち込んで三門だか木暮にラストパスしたけどGKにクリアされたシーンがあった。あそこでちゃんとパスがつながらないのがにんともかんとも。
アトムのFKも枠に行ってないし。

まあでも勝った。勝点35、15位甲府と勝点差5、16位浦和とは差6。
残留に向けて1歩前進だ。
次はホームで福岡戦。残り試合でもっとも勝ち点3が取れそうな試合だ。負けられない。

October 15, 2011

今週のご飯

今週は結構料理した。
火曜日、サンマの酢入り煮物を作った。
ネットでレシピを検索して、足りなかったしょうがを買ってきてつくってみた。
まあまあの出来。


木曜日、10/13はさつまいもの日。
たまたまさつまいもがあったのでさつまいもご飯を作ってみた。
しょうゆと酒とサツマイモを加えてご飯を炊くだけだが^^;
うまく出来た。
Satsumaimogohan


金曜日、サンマの煮物のために買ったしょうがが余っていたので豚肉のしょうが焼きを作ってみた。
ボールにしょうゆ、酒、みりん、砂糖、すりおろしたしょうを入れてたれをつくり、豚肉を入れてたれを絡めて20分ほど置いておく。
20分たったらフライパンで焼く。
出来上がったものは定食屋のしょうが焼きとは違う感じ。
まあ肉が豚こまだからなあ。定食屋のしょうが焼きで豚こまは使わないよなw
食べてみるとしっかりしょうが焼きでおいしかった。


どれも簡単でなかなかおいしかった。
来週も作ろう^^

Androidアプリ開発メモ027:画面の向き

表示の向きの設定

デフォルトではデバイスを回転させたときに画面の表示が縦長・横長に変化する。
この画面表示の変化に対する設定は、AndroidManifest.xmlでActivity要素のandroid:screenOrientation属性で指定する。

<activity
  android:name=".DisplayExample"
  android:label="@string/app_name"
  android:screenOrientation="portrait">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

android:screenOrientation属性の値は以下。

unspecified デフォルト。システムが向きを選択する。
portrait 縦長表示固定。
landscape 横長表示固定。

他にuser,behind,sensor,nosensorがあるが、上記の3つを覚えていればいいだろう。
ちなみにsensorと指定したところ、Xperia rayで少し試した程度だがunspecifiedと同じだった。

表示の向きの取得

現在の表示の向きはDisplay#getRotation()で取得できる。

android.view.Displayクラス
public int getRotation()
"自然な"方向からの画面の回転を返す。
戻り値はSurface.ROTATION_0(回転なし)、Surface.ROTATION_90、Surface.ROTATION_180 または Surface.ROTATION_270。

screenOrientation="unspecified"なサンプルアプリを実機で動かすと、以下のようになった。
1.デバイスを普通に縦に持った状態
Androidrotation1

2.デバイスを1から左に90度回転状態
Androidrotation2

3.デバイスを1から右に90度倒回転状態
Androidrotation3

4.デバイスを1から左に180度回転
Androidrotation4

"自然な"方向から表示の向きの時計回り方向の角度を定数で返しているのかな。
180度回転したら縦長表示になると思ってたが、横長表示のままだった。

サンプルアプリのコードは以下。

package com.example.displayexample;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;


/**
 * Display#getRotation()で返ってくる値を確認するサンプル
 */
public class DisplayExample extends Activity {
  
  private Display display;
  
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    final TextView textView = (TextView)findViewById(R.id.textView1);
    Button button = (Button)findViewById(R.id.button1);
    
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    display = wm.getDefaultDisplay();
    
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        int rotation = display.getRotation();
        String strRotation;
        switch (rotation) {
        case Surface.ROTATION_0:
          strRotation = "0";
          break;
        case Surface.ROTATION_90:
          strRotation = "90";
          break;
        case Surface.ROTATION_180:
          strRotation = "180";
          break;
        case Surface.ROTATION_270:
          strRotation = "270";
          break;
        default:
          strRotation = "null";
        }
        textView.setText("getRotation=" + strRotation);
      }
    });
  }
}

参考ページ:
画面の向き(ScreenOrientation) - Android Wiki*
Android, 画面の幅・高さ・傾きを調べる : Serendip - Webデザイン・プログラミング

October 14, 2011

新潟生存戦略

ピングドラムは見てません。途中から録画してますがw


今週のサカダイの残留争いの特集で、新潟16位で降格と予想した人が15人中5人。
ちなみに福岡、山形はチームの番記者以外全員が降格と予想し、その次に多かったのは甲府、さらに浦和と続いた。
大宮は謎の残留力(?)を持っているからか、降格と予想した人は一人もいなかった。


残留に向けて、新潟でいい感じなところは
・最近のリーグ戦、ナビスコカップでは、残留争いをしているチームの中でいちばん点を取れている(横浜戦4得点、ナビスコ名古屋戦90分で2得点)。
・得失点差が-3で、残留争いしているチーム中では浦和と並んでトップ。
・ヨンチョルが少し良くなってきたように思う。
・川又がナビスコ、天皇杯で点取った。この勢いでリーグ戦でも点取ってくれる、かも?

新潟は今までも得点機はあったのに決めれてなかった。
それが最近、得点できるようになった。
この調子が続けば。続くか…?


嫌な感じのところは
・残り試合で上位チームとの対戦が多い(柏、ガンバ、名古屋)。
・オリンピック予選で主力選手が取られる(高徳、大輔)。

やはり新潟がきついのは柏、ガンバ、名古屋との戦いが残っていることだ。
この3試合、はっきり言って勝つのは難しいだろう。勝ち点1でも取れたらいいと思う。
#柏は勝負弱い感じがするので、「首位」あるいは「勝てば首位」という状況だったらコロっと負ける可能性はあるかも。
残りの川崎、福岡、甲府の3試合で2勝すれば+6で勝ち点38。1勝1分1敗なら+4で36。


相手として甲府だけ考えると、甲府は得失点差が悪いので新潟を勝ち点で超えないと残留できない。
勝ち点39(+12):4勝2敗、3勝3分
勝ち点38(+11):3勝2分1敗
勝ち点37(+10):3勝1分2敗、2勝4分
勝ち点36(+9):3勝3敗、2勝3分1敗
勝ち点35(+8):2勝2分2敗、1勝5分
対戦相手はC大阪、清水、横浜、磐田、新潟、大宮。最後2試合がライバル相手。優勝争いに絡んでいるチームはない。
1敗しかしない、あるいは3勝するのってかなり厳しいと思う。
とすると、新潟としては残り6試合で1勝1分4敗でも残留はできそうな感じがする。

でも、ペシミストのおいらは不安でたまらない。
次節の相手の川崎は不調だったが、稲本が戻ってきて憲剛とのボランチコンビで手強そうだし、福岡は連勝中だし。


もしハーフナーが点取りまくって甲府が3勝以上したら、それはもうどうしようもないな^^;
逆に、ハーフナーはイエローもらって累積警告で2試合出場停止になったら、その瞬間甲府は詰む。

October 11, 2011

Androidアプリ開発メモ026:Notification

NotificationManager
Notificationはステータスバーに出る永続的な通知である。
サービスなどフォアグランドタスクでないものがユーザに通知する場合に使える。
使用するには、まずセンサーの利用でも出てきたgetSystemSerivice()を使ってNotificationManagerを取得する。getSystemService()の引き数はContext.NOTIFICATION_SERVICE。

Notificationの表示、キャンセルはNotificationManagerの以下のメソッドを使用する。

android.app.NotificationManagerクラス
public void notify(int id, Notification notification)
ステータスバーに表示されるNotificationをポストする。もし同じIDのNotificationがあなたのアプリによってポストされていてまだキャンセルされていない場合、更新された情報によって置き換えられる。
id:あなたのアプリでユニークなこのNotificationの識別子
android.app.NotificationManagerクラス
public void cancel(int id)

Notification
Notificationの生成はAndroid 3.0以降ではNotification.Builderを使う推奨されている。タブレット向けAndroidのスマートフォン向けAndroidが統合されたら、スマートフォンでもNotification.Builderを使うやり方が推奨になると思う。
Notification.BuilderはAndroid 3.0以降なので、現状ではスマートフォン向けAndroidではコンストラクタを使う。

android.app.Notificationクラス
public Notification(int icon, CharSequence tickerText, long when)
廃止予定。代わりにNotification.Builderを使え。
icon:ステータスバーに表示するアイコンのリソースID
tickerText:Notificationが最初に有効になったときに短時間表示されるテキスト
when:時間フィールドに表示する時間。System.currentTimeMillis時間ベース。
whenは何秒間表示するという表示時間の指定ではなく、ステータスバーが下方にドラッグされたて表示される一覧において、そのNotificationのエントリーの時間フィールドに表示される時間である。普通は System.currentTimeMillis()でよい。 setLastEventoInfo()でステータスバーが下方にドラッグされたときに表示される情報をセットする。
public void setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)
廃止予定。代わりにNotification.Builderを使え。
標準の"Last Event"レイアウトのビューであるcontentViewフィールドをセットする。
そのビューではiconとwhenをアイコンフィールドと時間フィールドに使う。
contentTitle:拡張エントリーに入るタイトル
contentText:拡張エントリーに入るテキスト
contentIntent:ユーザが拡張Notificationをクリックしたときにランチするインテント。
setLastestEventInfo()の引数に使用するPendingIntentはPendingIntentクラスのstaticメソッドで取得する。
android.app.PendingIntentクラス
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags)
戻り値:与えられたパラメータに合ったPendingIntent。FLAG_NO_CREATEの場合、NULLかもしれない。
requestCodeはstartActivityForResult()のrequestCodeと同じだと思う。 flagの意味はリファレンスを読んだけど良くわかりません。

// ノーティフケーションマネージャの取得
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

// ノーティフケーションオブジェクトの生成・設定
Notification notification = new Notification(R.drawable.n1, "テスト通知", System.currentTimeMillis());

Intent intent= new Intent(this, com.example.notificationexample.NotificationExample.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
notification.setLatestEventInfo(this, "テストの通知", "テストの通知のテキスト", pendingIntent);

// ノーティフィケーションの表示
nm.notify(notification_id, notification);

設定によっては、一定時間で消える、振動させる、LEDを光らせる、なんてこともできるらしい。

参考:
サービスとNotification - 愚鈍人
Androidのド肝 >> ステータスバーに通知する(NotificationとNotificationManager)

靴が小さかった

普段履きの靴がだいぶボロボロになっていたので、先日、新しい靴を買った。
前の靴は少し大きめな感じがしていたので、サイズはそれより0.5cm小さい24.5にした。

で、その新しい靴で歩いたら、指先が痛いorz
少し歩けばなじむかと思ったが、数百メートルで挫折。
結局、同じ靴で25.0のものを買いなおしてそれを今履いている。

24.5の靴は一応試し履きして、いけると思ったんだけどなあorz

October 09, 2011

Androidアプリ開発メモ025:モーションセンサー その2

前のモーションセンサーに関する記事でハイパスフィルタ、ローパスフィルタについては少し触れたが、正確に理解していたわけではないので、Android SDK グループのディスカッションに投稿して聞いた。
下記ブログがわかりやすいかも。まあ、離散数学(に限らず数学全般)がわかっていない自分としては完全に理解したとはとても言いがたいが^^;

加速度センサ と ローパスフィルタ (波形) | アンドロイドな日々

自分は前述のようにGoogleグループのAndroid SDK グループに入ったが、Googleグループにはほかに日本Androidの会ってのもある。というか、後者のほうがメンバーが全然多い。
日本Androidの会の方にも入っておこう^^;

センサの取得
まずSensorManagerをContext#getSystemSevice()で取得する。

android.content.Contextクラス
public abstract Object getSystemService(String name)
nameによってシステムレベルサービスのハンドルを返す。
name:センサーマネージャを取得する場合はContext.SENSOR_SERVICE。
ほかにWINDOW_SERVICE,LAYOUT_INFLATER_SERVICE,ACTIVITY_SERVICE,POWER_SERVICE,NOTIFICATION_SERVICEなどなど。
戻り値:サービス。nameが存在しない場合はnull
SensorManagerを取得したら、それからgetDefaultSensor()かgetSensorList()でandroid.hardware.Sensorを取得する。
android.hardware.SensorManagerクラス
public Sensor getDefaultSensor(int type)
与えられたタイプのためのデフォルトセンサーを得るためにこのメソッドを使う。返されたセンサーは複合センサーで、そのデータは平均化またはフィルタリングされている可能性があることに注意。もし生の線さにアクセスする必要があれば、getSensorListを使え。
type:要求されるセンサのタイプ。
Sensor.TYPE_ACCELEROMETER:加速度センサ
Sensor.TYPE_ORIENTATION:向き、傾きセンサ。廃止予定
戻り値:要求されたタイプとマッチするデフォルトセンサ。
android.hardware.SensorManagerクラス
public List<sensor>getSensorList(int type)
利用できるセンサのリストを得るために使う。
WEBに載ってるサンプルコードではgetSensorList()でセンサーの配列を取得して先頭のセンサーを使うものが多いが、getDefaultSensor()のソースを見ると中でgetSensorList()を呼んでリストの先頭のセンサーを返しているだけ(リストが空ならnullを返す)なので、現状では簡単にgetDefaultSensor()を使えばいいと思う。

SensorEventListener
センサーのイベントリスナandroid.hardware.SensorEventListenerインタフェースは次の2つのメソッドを持つ。

public abstract void onSensorChanged(SensorEvent event)
センサーの値が変化した際に呼ばれる。

public abstract void onAccuracyChanged(Sensor sensor, int accuracy)
センサーの精度が変化した際に呼ばれる。
SensorManagerに対するリスナの登録・解除は以下のメソッドを使用する。
android.hardware.SensorManagerクラス
public boolean registerListener (SensorEventListener listener, Sensor sensor, int rate) 
センサーにイベントを登録する。
rate:センサイベントが通知されるレート。これはただのシステムへのヒントである。イベントは指定されたレートより速くまたは遅く受信される可能性がある。普通はより速く受信される。値はSENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTESTのうちの1つか、イベント間の求められる遅延(単位はマイクロ秒)でなければならない。
rateの値は以下の規定値がmsecでの指定となる。
SENSOR_DELAY_NORMAL:画面の向きの変化に適したレート(デフォルト)
SENSOR_DELAY_UI:ユーザーインタフェースに適したレート
SENSOR_DELAY_GAME:ゲーム適したレート
SENSOR_DELAY_FASTEST:可能限り速く
android.hardware.SensorManagerクラス
public void unregisterListener (SensorEventListener listener, Sensor sensor) 
センサーからイベントを登録解除する。
実機(Xperia ray)でSENSOR_DELAY_NORMALの場合、200ミリ秒毎にセンサイベントが発生する。

実装例:

public void onCreate(Bundle savedInstanceState) {
  // ビューの処理とか
  
  // センサーマネージャの取得
  sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
  
  // センサーの取得
  accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  orientation = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);	// TYPE_ORIENTATIONは廃止予定
}

@Override
protected void onResume() {
  super.onResume();
  
  // リスナの登録
  if (accelerometer != null) {
    sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
  }
  if (orientation != null) {
    sensorManager.registerListener(this, orientation, SensorManager.SENSOR_DELAY_NORMAL);
  }
}

@Override
protected void onStop() {
  super.onStop();
  
  // リスナの登録解除
  if (accelerometer != null) {
    sensorManager.unregisterListener(this, accelerometer);
  }
  if (orientation != null) {
    sensorManager.unregisterListener(this, orientation);
  }
}

/**
 * センサの値の変更時の処理
 */
@Override
public void onSensorChanged(SensorEvent event) {
  // 加速度の処理
  if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    // X軸加速度
    gravity[0] = ALPHA * gravity[0] + (1 - ALPHA) * event.values[0];
    acceleration[0] = event.values[0] - gravity[0];
    // Y軸加速度
    gravity[1] = ALPHA * gravity[1] + (1 - ALPHA) * event.values[1];
    acceleration[1] = event.values[1] - gravity[1];
    // Z軸加速度
    gravity[2] = ALPHA * gravity[2] + (1 - ALPHA) * event.values[2];
    acceleration[2] = event.values[2] - gravity[2];
  }
  
  // 方位角、ピッチ、ロールの取得
  if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
    azimuth  = event.values[0];	// アジマス(方位角)
    pitch = event.values[1];	// ピッチ
    roll = event.values[2];	// ロール
  }
  
  // TODO:表示するとか何か
}

/**
 * センサの精度変更時の処理
 */
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
  // TODO:何か処理
}
しつこいようだけど自分の数学の知識ゼロなので、以下の記述の信頼性もゼロです^^;

加速度はセンサの生値をローパスフィルタ(指数加重平均)を通して重力加速度を取得して、生の値からそれを引いて重力加速度の影響を除外した加速度を算出しているつもり。
ローパスフィルタの処理は重力加速度を算出されると思うのだが、掲示板でそういうことでしょ?と聞いたら、
「違うと思う。単に高周波をカットしているだけだ。」
と言われた。高周波をカットした値を加速度として使えと。
しかし、APIリファレンスのSensorEventに載っているサンプルコードではローパスフィルタを通して重力を算出しているように思えたけどなあ。
ローパスフィルタを通した値は、重力の影響だけ強く残った、実際の加速度とは大きく乖離した値になると思うんだけど。
方位の方は生の値をそのまま使っている。これも加重平均を取った方がいいと掲示板で言われたが、それだと値が収束するまですごい時間がかかる。粘性の高い油の中に磁石があるみたい。方位知るのに5秒も10秒も待たされるのは、どうもなあ。

BS11でエスカフローネ再放送

アニメ 天空のエスカフローネ | BS11


うわ、なっつかしー。
しかしなんでこれが今再放送されるんだと思ったが、来春にBlu-ray Boxが出るのね。なるほど。
この枠はBlu-rayが出る昔のアニメの再放送枠なのかな。

買わないよw
欲しいけどね、買わないよ。たぶん。。。

October 08, 2011

Androidアプリ開発メモ024:モーションセンサー

リファレンスのSensorEventのSensor.TYPE_ACCELEROMETERとSensor.TYPE_ORIENTATIONの部分を訳してみた。

以下、怪しい訳

------
Sensor.TYPE_ACCELEROMETER:
すべてのvaluesははSI単位系(m/s^2)である。

  values[0]:Gxを引いた、X軸上の、加速度
  values[1]:Gyを引いた、Y軸上の、加速度
  values[2]:Gzを引いた、Z軸上の、加速度

このタイプのセンサーはデバイスに加わった加速度(Ad)を測る。概念的には、それはセンサー自体に加わった力(Fs)を測ることによって次の関係を使って行われる。

  Ad = ΣFs/mass

特に、重力の力は測定される加速度に常に影響している。

  Ad = -g - ΣF/mass

従って、デバイスが置いてあって(明らかに加速していない)時、加速度計はg=9.81m/s^2の大きさを読んでいる。
同様に、デバイスが自由落下にしていてそれゆえ地面に向かって危険なほどに、9.81m/s^2で加速している時、加速度計は0m/s^2を読んでいる。
デバイスの実際の加速度を測定するために、重力の力の寄与を排除しなければならないことは明白である。これはハイパスフィルターを適用することによって達成できる。逆に、ローパスフィルタは、重力の力を分離するために使用することができます。

<<サンプルコード>>

例:
・デバイスがテーブルの上に寝ていて左側を右に押された場合、X加速度値は正である。
・デバイスがテーブルの上に寝ている場合、加速度値は+9.81であり、重力の力(-9.81m/s^)を引いたデバイスの加速度(0m/s^2)と一致する。
・デバイスがテーブルの上に寝ていて空に向かって加速度Am/s^2で押した場合、加速度値は重力の力(-9.81m/s^)を引いたデバイスの加速度(+Am/s^2)と一致するA+9.81である。


Sensor.TYPE_ORIENTATION:
すべてのvaluesは度で表された角度である。
  values[0]:方位角、磁北方向とY軸の間の、Z軸周りの角度(0~359)。0=北、90=東、180=南、270=西。
  values[1]:ピッチ、X軸周りの回転(-180~180)で、Z軸からY軸へ向かって動く場合に正の値。
  values[2]:ロール、Y軸周りの回転(-90~90)で、X軸からZ軸へ向かって動く場合に正の値。

注意:この定義は、X軸が飛行機の長辺(機首から尾部)に沿っている航空で使用されているヨー、ピッチおよびロールとは異なります。

重要な注意:このセンサーのタイプは、レガシーの理由で存在しており、代わりにこれらの値を計算するためにremapCoordinateSystem()とgetOrientation()と組み合わせてgetRotationMatrix()を使用してください。

-----怪しい訳ここまで。

加速度センサーについては、
・ハイパスフィルタ:重力の影響を取り除く。
・ローパスフィルタ:重力を取り出す。
ということらしい。

一般的には
・ハイパスフィルタ:緩慢な変化をカットして急激な変化のみを取り出す。
・ローパスフィルタ:急激な変化をカットして緩慢な変化のみを取り出す。
だそうだ。ローパスフィルタを通すと関数の定数項が取り出せて、ハイパスフィルタを通すと関数から定数項を取り除いたものが出てくるということか?理屈はわからない。
サンプルコードの計算式がなんでローパスフィルタになるのかも理解できない。

数学をもっとちゃんと勉強しておくんだった…。

座標系
デバイスを縦に持ってディスプレイを自分のほうに向けた場合、
X軸:左から右
Y軸:下から上
Z軸:奥から手前

アジマス、ピッチ、ロール
リファレンスには飛行機のピッチ、ロールと違うと書いてあるが、飛行機や船のように考えるとわかりやすいような気がする。
デバイスを平面に置いてデバイスの上部を機首と考えると、
azimuth(アジマス、方位角):機首の向いている方角
pitch(ピッチ):機首や機尾の縦のゆれ(X軸回転)
roll(ロール):翼の方向の横揺れ(Y軸回転)

今読んでいるAndroidアプリ開発の本でピッチ、ロールの説明の図、間違ってるような気がする。
著者にメールしてみた。。返事が来るかわらかないけど。

October 07, 2011

iphone4s予約開始

ニュースでiphone4sの予約が今日から始まって、朝から家電量販店で並ぶ人の様子が映し出されていた。
やっぱ人気あるんだな。iphone。
android機を予約するための行列が朝から出来るなんてあり得ないし。


apple1社のiphoneと多数の会社から端末が出ているandroid搭載のスマートフォン。
そう遠くないうちにandroidの方が優勢になると思っていたが、どうやらそうでもなさそうだなあ。

日本株のパフォーマンスの悪さの理由

今日のマネックス証券のレポートで、アメリカと比べて日本株のパフォーマンスが悪いのは民主党政権が円高を放置しているからだという説明をしていた。
同意できない。


日本株のパフォーマンスが悪い理由なんか簡単だ。
日本のGDPが増えていないから。
その間、アメリカはGDPがちゃんと増えている。
アメリカのGDPが増えて日本のGDPが増えない理由は、あちらは人口が増加していてこちらは人口が横ばい~減少だから。
なんの難しいこともない。


前にも同じようなことを書いたが、ネットでは
・移民は受け入れない。
・出生率増加のための積極的な手段(子ども手当とか)も講じない。
・TPPにも参加しない。
という意見が多いが、それでどうして経済が維持できるだろうか。
「日本にはもの作りの技術があるから大丈夫」と言っている人がいるけど、幻想だ。
だいたい、「もの作り」っていうなら、そのもの作りを支えている技術者の待遇の悪さは何なんだろう。
欧米では優れた技術を持つ人は尊敬されるだけではなくそれなりの収入も英テイルものだが、日本では尊敬しか得ることが出来ない。
日本では、中村修司のように経済的見返りを得ようとすると叩かれる。


政治家は次の選挙のことしか考えていない。
官僚は天下りの今年か考えていない。
市民は明日の生活のことしか考えていない。


現状維持してたら、ゆっくりと衰えていくばかりなのに。

October 06, 2011

ナビスコカップ準々決勝、新潟、磐田ともに敗れる

これに勝てば2000万円だったのになあ。


J's GOAL:試合詳細:2011 ヤマザキナビスコカップ 準々決勝 ガンバ大阪 3-1 ジュビロ磐田


遠藤も明神もいないガンバ相手でこのスコア、力の差は大きいわ。


J's GOAL:試合詳細:2011 ヤマザキナビスコカップ 準々決勝 名古屋グランパス 5-3 アルビレックス新潟


1試合でロスタイムに失点×3回って、本当に真面目に試合やってんのかと疑いたくなる。
結果を考えると、川又の得点って余計な疲労を増やしただけだ。
今週末にリーグ戦がないのが救いだな。天皇杯はあるけど。

このJ1初得点を記念にして、川又は本当に来年どっかに行って欲しい。
今シーズン終了後にフロントがまた
「来年は川又の成長に期待する」
と言ってまともなFWを取らなかったら、新潟を応援する気が失せる。

October 02, 2011

第28節、磐田追いついてドロー、新潟8試合ぶり勝利

J's GOAL:試合詳細:2011 J1 第28節 モンテディオ山形 1-1 ジュビロ磐田


どっちのサポにとっても誰得な試合。
山形サポは「勝ち点1じゃ意味ねーよ。」だろうし、磐田サポは「降格圏のチームに何やってるんだよ。」だろう。
まあ、前田のゴールはすばらしかったが、それだけ。


J's GOAL:試合詳細:2011 J1 第28節 アルビレックス新潟 4-2 横浜Fマリノス


菊地が出場停止だし、絶対勝てないと思っていたら、勝った。
村上がすばらしいクロスで2アシスト。特に1点目のヨンチョルへのクロスは良かったねー。
高徳はリーグ戦初ゴール。初だったんだ。セリエAのチェゼーナが獲得しようとしている報道があるけど、本当かね?
行かないでほしいけど、もし行くなら複数年契約してから移籍金を置いて行ってくれ^^;

ナビスコで久しぶりに勝って、選手の精神面に良い影響を及ぼしたのか。
ヨンチョルは良くなってきてるみたいだし少し期待が持ててきた?
まあ、終了間際の失点は相変わらずだが^^;

2011年9月末終了アニメ感想

良かった方から感想を。

TIGER & BUNNY
・さほど期待してなかった、すごくおもしろかった。
・ヒーロー役の声優陣が良かった。
・ウロボロスの正体はわからずじまいだし、ルナティックと決着はついてないし、2期を期待させる終わり方。


STENIN'S GATE
・ゲームは未プレイだが、楽しめた。
・Dメールした後、元の世界線の岡部はどうなるん?


花咲くいろは
・中盤まではおもしろかったが、最後の方、旅館をやめる/やめないの話になってからは盛り下がってつまらなくなった。主人公以外の旅館の従業員が自己中で嫌な人たちになっちゃって。まあ「やっぱり旅館続けます」みたいなご都合主義にならなかっただけマシか。


神様ドォルズ
・1クールで終わり?何も解決しないで終わりだし、2期やるほど盛り上がったとは思えないし。アニメとして良いものを作ろうという気が制作側にあったのか疑問。なんかマンガの宣伝して、ロリと巨乳のキャラソン出してちょっと儲けようみたいなつもりだったのでは?という感じがする。


BLOOD-C
・最初の3,4話は毎回同じ構成。中盤からはひたすら虐殺の嵐。13話も使うほどの話ではない。
・勝手な想像だが、CLAMPの脚本が遅くて、仕方なく藤咲さんが「とりあえず戦闘シーンは入れた」みたいなやっつけの脚本を書いてたんじゃないか。
・戦闘シーンの作画が酷過ぎる。小夜も古きものもまったく強そうな感じがしない(最終話はそうでもなかったが)。手が6本だが8本ある敵の時なんか、もうあまりにお粗末さに失笑してしまった。動画における戦闘の「動き」がまったく迫力不足。やっぱり脚本が遅れて時間不足だったんじゃね?最近のアニメでここまで酷い作画は珍しい。
・最後の方の大虐殺は、なんというか、アホらしくて笑ってしまった。ギャグアニメですか?
・決着は劇場版でってことか。なんか見てた人をバカにしてるような気がする。


青の祓魔師
・監督が岡村天斎ということで期待したが途中で視聴中止。なんの深みも、意外な展開もないストーリー。原作に沿った展開だったのだろうか、とにかく「次回が楽しみ」と全く思えなかった。岡村天斎は話作りがうまい、オリジナル作品向けの監督なのかな。


あと、今期のアニメじゃないけど、録画してあって最近見たものについて。

続・夏目友人帳
・主人公の言動にイライラした。
「妖にお節介を焼いてひどい目に遭う。」
という話の繰り返し。全く成長がない。最近「主人公が優しさが良かった」という3期を見ての感想をどこかで読んだが、あれは優しいというよりバカで優柔不断で八方美人だろう。何度も妖にだまされているのに全然懲りずに妖を助けようとするし、素質を生かして身を守る術を覚えればいいのに全くそういうことをしないし。ニャンコ先生がいなけりゃとっくに死んでる。
・1期見たときは全くネガティブな印象を受けなかったんだけどなあ。
・3期も録画してあって少し見たが、続きを見る気が今はしない。
・4期も決まったという。そんなに人気あるんだ。神谷浩史人気?

« September 2011 | Main | November 2011 »

March 2017
Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof