ActivityとServiceの連携

Serviceと連携したいときの手順メモ。
基本的にここに書いてあるのと同じ。

基本

1. Service側: IBinderをimplementsしたオブジェクトを用意し、Service#onBind()の戻り値として返す。
2. 呼び出し側: ServiceConnectionをimplementsしたオブジェクトを用意し、これをContext#bindService()に渡す。
3. 呼び出し側: ServiceConnection#onServiceConnectedにIBinderが渡ってくるので、これを取得する。

IBinderを取得すると、これを介してServiceと通信できるようになる。

詳細

Android Developersによると、Serviceとの連携方法には「IBinderをimplementsしたオブジェクトを用意する方法」によって三種類ある。

  • 自分でBinderを継承する。            → 呼び出し側とService側が同一プロセスのときのみ使用可能。
  • Messenger#getBinder()で生成する。     → 呼び出し側とService側が別プロセスでも使用可能。
  • aidlファイルから生成されたstubクラスを継承する。→呼び出し側とService側が別プロセスでも使用可能。

以下詳細を列挙する。

自分でBinderを継承する

呼び出し側とService側が同一プロセスのときのみ使用可能。
デフォルトの設定では全てのコンポーネント(activity,service,receiver)は同一プロセスで実行されるようになっているので、
なにもしなければこの要件は初めから満たしている。
個人的な経験則からいうと、Androidコンポーネントは一部の例外(OutOfMemoryを起こしやすい処理等)を除いては
プロセスを分割すべきでないと感じたので多くの場合はこの方法で十分だと思う。

Messenger#getBinder()で生成する

呼び出し側とService側が別プロセスでも使用可能。
MessengerはAIDLよりも簡易なプロセス間通信を実現するために用意されているもので、その実体は単にAIDLのラッパーである。
Android Developersによると、多くのアプリではAIDLを直接利用する必要はなく、Messengerを使用するべきであると記されている。

Service側
まずHandlerを継承し、handleMessage()をオーバーライドしてメッセージを受信したときの処理を書く。
次に継承したHandlerを引数にしてMessengerのインスタンスを作成し、getBinder()の戻り値をonBind()で返す。

public class MyService extends Service{
  class IncommingHandler extends Handler{
    @Override
    public void handleMessage(Message msg){
      //メッセージを受信したときの処理
    }
  }

  Messenger mServiceMessenger = new Messenger( new IncommingHandler() );

  @Override
  public IBinder onBind(Intent intent) {
    return mServiceMessenger.getBinder();
  }
}

呼び出し側
onServiceConnected()でIBinderからMessengerを生成する。

public void onServiceConnected(ComponentName className, IBinder service) {
  mServiceMessenger = new Messenger(service);
}

メッセージを送るときはこんな感じ。whatには任意のint値を指定できる。

Message msg = Message.obtain(null, what, 0, 0);
try {
  mServiceMessenger.send(msg);
} catch (RemoteException e) {
  e.printStackTrace();
}

MessageオブジェクトはServiceで用意したHandlerのhandleMessageメソッドに渡される。
上記の方法はServiceで生成したMessengerを呼び出し側に渡す方法だが、このあと呼び出し側で生成したMessengerをServiceに渡すことができる。

Message msg = Message.obtain(null, what, 0, 0);
msg.replyTo = mActivityMessenger;
try {
  mServiceMessenger.send(msg);
} catch (RemoteException e) {
  e.printStackTrace();
}

同じくService側のhandleMessage()に渡される。

aidlファイルから生成されたstubクラスを継承する

呼び出し側とService側が別プロセスでも使用可能。
Androidのプロセス間通信メカニズムであるAIDLを使用する。
詳細は省略。

getJSONを使うためのクライアントサイド/サーバーサイドの実装


JQueryにはgetJSONという便利なメソッドがあるのだが、
クライアントサイド/サーバーサイドの双方から使い方を解説している記事を見かけなかったので、
メモとして残しておく。


例えばサーバーから以下のようなjsonオブジェクトを取得したいとする。

{ 'title' : 'foo', id' : 'foo_id' }

クライアントからの呼び出しは、例えばこうなる。

var CGI_URL = "http://example.com/cgi";
$.getJSON( CGI_URL + "?callback=?", null, function( data, status ){
  document.body.innerHTML = "<h1>" + data.title + "<h1>" + data.id
}

jsonが取得できるとコールバックが呼ばれる。
dataが取得したjsonオブジェクト、statusがリクエスト結果を表す文字列。

「callback=?」の部分はJQueryによって適当な関数名、例えばjQuery15019275276153348386_1303305468939に置き換えられる。

サーバー側にはcgiパラメータcallbackが渡されてくるので、それを使ってこんなjavascriptを返す。

jQuery15019275276153348386_1303305468939({ 'title' : 'foo', id' : 'foo_id' })

これをクライアントサイドで実行すれば、jQuery15019275276153348386_1303305468939に格納されたコールバックがjsonを引数にして呼び出される。
(実行はJQueryが勝手にやってくれる)

これを実現するサーバーサイドの実装はこうなる。(ruby)

require "cgi"
cgi = CGI.new
print "Content-Type: application/javascript;charset=utf-8\n\n"
print cgi["callback"] + "({ 'title' : 'foo', 'id' : 'foo_id' })"

cgiパラメータとして渡されてきたcallbackをjsonを引数にして呼び出すjavascriptを返しているだけ。

GBookmark is released.

descriptions

GBookmark is Google Bookmark Client.
If you have been use Google Bookmark(http://www.google.com/bookmark/),download me!

Feature:

  • Desktop Shortcut
  • Auto Synchronization.
  • Add, Edit, Delete Bookmark.
  • Search bookmark from title,label and note.
  • Support label separator for tree view.
  • Support Favicon download.
  • Support Live Folder.

Implementation Plan:

  • sort by access time.
  • UI fix.

requirement

android OS 1.6 later.

history

V0.8.9.0

  • add Desktop Shortcut support! (Long-press label or bookmark).
  • bugfix.

V0.8.8.7

  • bugfix.

V0.8.8.1

  • add New Option - Show Label Separator.(default: show)
  • bugfix(item title indicate single line).

V0.8.8.0

  • add Web Login interface.
  • add New Option - Default Sort Mode.
  • bugfix.

V0.8.7.6

  • add new option. ( enable Incremental Search )
  • bug fix.

V0.8.7.3

  • bug fix.

V0.8.7

V0.8.6.2

  • bug fix.

V0.8.6.1

  • bug fix.

V0.8.6

  • bug fix.

V0.8.5

  • add new auto-complete mode.

V0.8.4

  • add auto-complete for label editing.
  • adjust synchronization.

V0.8.2

  • add Live Folder support.
  • fix search box issue for Android OS 1.6

v0.8.0 release.


first setup

1. First, you need to enter user name and password for Google Bookmark.
then press "submit" button.

2. If your login is successful, synchronization is automatically started.


Preference

If you want to configure Sync schedule,appearance, and more, press menu key and select preference.

eclipseで既存のソースコードを取り込んだ時にプロジェクト作成に失敗する。

eclipseではcreate project from existing sourceを選択することで、既存のソースコードを取り込んで新規プロジェクトを作ることができます。
しかし、これがたまに失敗することがあります。原因はわかっているのですが、毎回そのことを忘れていてはまってしまうので、忘備録として書いておきます。

原因

結論からいうと、プロジェクトのルートとなるディレクトリをeclipseのworkspaceディレクトリ直下に配置してはいけません。
バージョン管理しているソースをチェックアウトするときも同様です。
別の場所やもしくはworkspace下にサブディレクトリを作ってそこに配置するといいでしょう。

エラー"Invalid project description"

これはeclipseワークスペースディレクトリにプロジェクトディレクトリと同名のディレクトリがあると発生します。
つまり、

workspace -
          + app-src

という配置になっているとき、app-srcをルートディレクトリとして新規プロジェクトを作成しようとすると、
eclipseに「app-srcをルートとするプロジェクトは(workspace直下にapp-srcというディレクトリがあるから)作れないよ」と怒られます。
解決策は先程述べた通り、app-srcを別のディレクトリに移動することです。

GBookmark is released.

descriptions

GBookmark is Google Bookmark Client.
If you have been use Google Bookmark(http://www.google.com/bookmark/),download me!

Feature:

  • Auto Synchronization.
  • Add, Edit, Delete Bookmark.
  • Search bookmark from title,label and note.
  • Support label separator for tree view.
  • Support Favicon download.

Implementation Plan:

  • Desktop Folder.
  • sort by access time.
  • UI fix.

requirement

android OS 1.6 later.

history

v0.8.0 release.


first setup

1. First, you need to enter user name and password for Google Bookmark.
then press "submit" button.

2. If your login is successful, synchronization is automatically started.


Preference

If you want to configure Sync schedule,appearance, and more, press menu key and select preference.

androidアプリ WOLショートカットをリリース



android market
(androidからアクセスして下さい)

概要:

Wake-On-Lanを利用して、無線lan経由でPCの電源をONにできるアプリです。
利用に当たっては、マザーボードやネットワークカードがWakeOnLanをサポートしている必要があります。
作ったきっかけは、既存のWakeOnLanアプリがウィジェットは作れるのにショートカットは作れなかったりして起動方法の幅が狭いことに不満を覚えたからです。

特徴:

  • 複数のPCの設定を作成し、いつでも起動できます。
  • デスクトップショートカットを作れます。
  • パケット送信前に確認ダイアログを表示できます。

インストール要件:

android OS 1.6以上

更新履歴

Ver1.4 横画面レイアウトの調整。クラッシュバグの修正。
Ver1.3 キャンセルボタンが機能していない問題を修正。
Ver1.2 バグフィックス
Ver1.1 設定をSDカードにエクスポート出来るようにした。日本語ロケールの追加
Ver1.0リリース

subversionのリビジョン番号の振る舞い

今までプロジェクト毎に別々のsubversionリポジトリを作って運用していた。(ついでに言うとtrunkとかbranchesの使い分けもしていなかった。)
しかし管理が煩雑になってきたのでリポジトリを一つにまとめることを検討してみた。

複数のプロジェクトを一つのリポジトリで管理する場合、心配なのがリビジョン番号はどういう挙動をするのか? ということだ。
そこで簡単な実験をしてみた。

リポジトリの作成

project1及びproject2をtest_repositoryで管理することを考える。

まずtest_repositoryリポジトリを作成し、チェックアウトする。

チェックアウトしたtest_repository作業コピーの下に以下のファイルを作成する。

test_repository/trunk/project1/a.txt
test_repository/trunk/project2/b.txt

そしてtest_repositoryをコミットする。このときのtest_repositoryの状態をリポジトリブラウザで閲覧すると以下のようになる。

ファイル リビジョン
test_repository/trunk rev1
test_repository/trunk/project1 rev1
test_repository/trunk/project1/a.txt rev1
test_repository/trunk/project2 rev1
test_repository/trunk/project2/b.txt rev1

project1の編集

次に、project1をチェックアウトする。project1/a.txtに書き込み、project1をコミット。
test_repositoryをsvn updateして状態を閲覧する。

ファイル リビジョン
test_repository/trunk rev2
test_repository/trunk/project1 rev2
test_repository/trunk/project1/a.txt rev2
test_repository/trunk/project2 rev1
test_repository/trunk/project2/b.txt rev1


さらにproject1/a2.txtを作成し、project1をコミット。test_repositoryをsvn updateして状態を閲覧する。

ファイル リビジョン
test_repository/trunk rev3
test_repository/trunk/project1 rev3
test_repository/trunk/project1/a.txt rev2
test_repository/trunk/project1/a2.txt rev3
test_repository/trunk/project2 rev1
test_repository/trunk/project2/b.txt rev1

新しく作成されたa2.txtのリビジョンがいきなり3になっているのがわかる。
リビジョン番号はリポジトリへのコミットごとに生成され、変更があったフォルダ/ファイルに割り当てられるようだ。

project2の編集

ここでproject2をチェックアウトし、project2/b.txtを編集する。コミットとアップデートをすると…

ファイル リビジョン
test_repository/trunk rev4
test_repository/trunk/project1 rev3
test_repository/trunk/project1/a.txt rev2
test_repository/trunk/project1/a2.txt rev3
test_repository/trunk/project2 rev4
test_repository/trunk/project2/b.txt rev4

作業コピーのログ

だいたいの振る舞いが分かってきたところで、それぞれの作業コピーのコミットログを見てみる。
test_repositoryのログ

リビジョン: 4 
変更 : /trunk/project2/b.txt

リビジョン: 3
追加 : /trunk/project1/a2.txt

リビジョン: 2
変更 : /trunk/project1/a.txt

リビジョン: 1
追加 : /trunk
追加 : /trunk/project1
追加 : /trunk/project1/a.txt
追加 : /trunk/project2
追加 : /trunk/project2/b.txt

project1のログ

リビジョン: 3
追加 : /trunk/project1/a2.txt

リビジョン: 2
変更 : /trunk/project1/a.txt

リビジョン: 1
追加 : /trunk
追加 : /trunk/project1
追加 : /trunk/project1/a.txt
追加 : /trunk/project2
追加 : /trunk/project2/b.txt

project2のログ

リビジョン: 4
変更 : /trunk/project2/b.txt

リビジョン: 1
追加 : /trunk
追加 : /trunk/project1
追加 : /trunk/project1/a.txt
追加 : /trunk/project2
追加 : /trunk/project2/b.txt

project1、project2共に自分の変更履歴だけが表示され、他のプロジェクトの履歴は表示されないことがわかる。

結論

  • リビジョン番号はコミット毎に一意の番号が付けられ、そのとき変更があったフォルダ/ファイルに同じ番号がつく。
  • 変更が無かったフォルダ/ファイルのリビジョン番号は更新されない。
  • 複数のプロジェクトを管理する場合、個々のプロジェクトのルートフォルダのリビジョン番号で個々のプロジェクトを管理することができる。
  • リビジョン番号はリポジトリ全体で共有されているので、複数のプロジェクトでコミットを繰り返すと、個々のプロジェクトでリビジョン番号が飛び飛びになる。
  • しかしながら、「変更を加える毎にリビジョンが上がる(連番でないにしても)」という原則は保たれているので、実使用上は問題ないかもしれない。

とりあえず大丈夫そうである。
問題は既存のリポジトリをどうやって(変更履歴を保ったまま)一つにまとめるかだが、「複数のリポジトリ まとめる」でググるといろいろ出てくるので、そこら辺を参考にしよう。