Android SDK WG 第2回 セッション (2008/11/29) Intent SDK WG 江川 崇 ©Japan Android Group, 2008 1 Intentってなに? IntentのJavaDocを見てみましょう URLはこちら http://code.google.com/android/reference/androi d/content/Intent.html ©Japan Android Group, 2008 2 JavaDocの冒頭 An intent is an abstract description of an operation to be performed. Intentとは実行される操作の抽象的な単位 です。 ©Japan Android Group, 2008 3 JavaDocの冒頭 It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent, Bundle) or bindService(Intent, String, ServiceConnection, int) to communicate with a background Service. It(Intent)は、アクティビティを起動するため にstartActivityで使われますし、 broadcastIntentであらゆる BroadcastReceiverコンポーネントに対して 送られます。また、startServiceや、 bindServiceでバックグラウンドのサービスと コミュニケーションをとるために使われます。 ©Japan Android Group, 2008 4 どういうことか? 前回のSDK WGのセッションで学んだこと 一つのアクティビティ内のウィジェットやイベント は単一のスレッドで実行される Handlerドリブン、Looperでのループ ・・・が、サービスや他のアプリは、同一のスレッド ではないし、プロセスも別な可能性あり ©Japan Android Group, 2008 5 どういうことか? やり取りする方法を開発者が作るとしたら? こいつは同じプロセスだけど別スレッドだから、 プロセス領域に置かれる変数などで、スレッド間 で共有する仕組みを使おう。 こいつはプロセスが別だから、プロセス間通信 の仕組みを使って送ろう。あるいは、プロセス間 で参照できるような共有メモリやセマフォなどを 使ってやろう タイミングや仕組みを気にせずに、やってくれ る仕組があればいいなあ ©Japan Android Group, 2008 6 Intentが楽にする この実現手段がIntent つまり アクティビティ サービス 他のアプリケーション などは、各々固有のライフサイクルがある。 Intentは、これらを実行時にくっつける 糊(のり)のような働きをする。 ©Japan Android Group, 2008 7 Intentのいいところ アプリケーションからはあくまでも「何をやり たいのか」を伝えるだけでよい スレッド間やプロセス間でありがちな、同期 や排他等をいちいち実装しなくてよい Intent = 「意図、意向」 仕組みの細部を意識することなくプロセス間 通信が実現できる 「適切」な宛先に対して、「適切」なタイミング で送り届けられる ©Japan Android Group, 2008 8 Intentの持つ属性 1809行目 private private private private private private private String mAction; Uri mData; String mType; ComponentName mComponent; int mFlags; HashSet<String> mCategories; Bundle mExtras; ©Japan Android Group, 2008 9 Action private String mAction; そのインテントが期待されている振舞いの分類 ・・・2種類ある。 Activity Action Activityを起動したいときに使うもの アノテーション @SdkConstantType.ACTIVITY_INTENT_ACTION Broadcast Action ブロードキャスト(全体周知)したいときに使うもの アノテーション @SdkConstantType.BROADCAST_INTENT_ACTION ©Japan Android Group, 2008 10 Action Activity Action 例) ACTION_VIEW・・・「何らかの表示をしたい」とき 558行目:public static final String ACTION_VIEW = “android.intent.action.VIEW”; 593行目:デフォルトはこれ ACTION_DIAL・・・「電話アプリ」を起動したいとき 851行目: public static final String ACTION_DIAL = "android.intent.action.DIAL"; ©Japan Android Group, 2008 11 Action Broadcast Action 例) ACTION_BOOT_COMPLETED ・・・システムの「起 動が完了した」とき 1096行目: public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; ACTION_CONFIGURATION_CHANGED・・・コン フィグの状態が変わったとき 1162行目: public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED"; ©Japan Android Group, 2008 12 Uri private Uri mData; このインテントの取り扱い方に関する情報 such as a person record in the contacts database 「連絡先データベースの人情報とか」 アクションと組み合わせて使うらしい ACTION_VIEW content://contacts/1 「識別子が1の人の情報を表示してほしい」 Dataと言っているが、具体的なコンテンツの中身 ではないので注意 ©Japan Android Group, 2008 13 Uri Uriクラス RFC2396やRFC2732で規定されているURI表現を 取り扱うことの出来るクラス 標準のjava.net.URIのようなもの java.net.URLEncoderとかを使っている URI表現の一般的な構成 [スキーム:]スキーム固有部分[#フラグメント] ex) http://www.example.com/index.html#p2 content://foo/bar mailto:[email protected] ©Japan Android Group, 2008 14 Uri なんでこんなことしてるの? プロセスをまたがったやり取りを実現する技術要 素は、多くの場合ハードウェアを超えて、ネット ワーク上の他のコンポーネントに対してアクセス することも想定している。 このようなケースでは、 宛先(あるいは情報のありか)の特定 操作(情報に対するI/Oなど)の表明 などを、ネットワーク上で使い勝手がよく一般に浸 透しているURI表現で実現することが多い RESTはHTTPを使って操作を定義 dRubyの「druby://」 ©Japan Android Group, 2008 15 でもちょっと問題が。。 • デバイス間Intentの廃止 • 原則として、Intentは同一デバイス内に限定 • In the end, we determined that the Intent system, as designed for local use, did not lend itself well to being the vehicle for a Remote Procedure Call (RPC). Android Developers Blog 2008/8/25 • Intentはローカルユースのために設計され ており、RPCの伝達手段としては役に立たな いものであると結論付けました。 ©Japan Android Group, 2008 16 Flags, Categories, Extras private int mFlags; Intentに対する特別な情報を持ったフラグ FLAG_*の定数参照 private HashSet<String> mCategories; アクションに対する追加情報(分類) IntentFilterなどを使う時にちょっと便利 private Bundle mExtras; アプリからの情報を出し入れできる入れ物 Bundleの66行目: new HashMap<String, Object>() ©Japan Android Group, 2008 17 ComponentName private ComponentName mComponent; インテントの宛先のこと 明示的なインテント(Explicit Intents) Intent(Context packageContext, Class cls)や、 setComponentメソッドなどによって、そのインテントを取 り扱うコンポーネントを「明示的」に指定されたもの 宛先を特定する情報は他には要らない 暗黙的なインテント(Implicit Intents) 宛先のコンポーネントを指定されていないもの そのIntentを動かすにあたってどのコンポーネントが最 適であるかを決定するための十分な情報が必要 ©Japan Android Group, 2008 18 実際にIntentを投げてみる StartActivityForResultを投げてみる Activity#startActivityForResult → Instrumentation#execStartActivity 1418行目 → 1437行目で int result = ActivityManagerNative.getDefault() .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token, target != null ? target.mEmbeddedID : null, requestCode, false, false); これは、ソース的には ActivityManagerNative#startActivity 979行目 が呼ばれている模様 ©Japan Android Group, 2008 19 ActivityManagerNative#startActivity :979行目 public int startActivity(IApplicationThread caller, Intent intent, ・・・) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeTypedArray(grantedUriPermissions, 0); data.writeInt(grantedMode); data.writeStrongBinder(resultTo); data.writeString(resultWho); data.writeInt(requestCode); data.writeInt(onlyIfNeeded ? 1 : 0); data.writeInt(debug ? 1 : 0); mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); reply.readException(); int result = reply.readInt(); reply.recycle(); data.recycle(); return result; } ©Japan Android Group, 2008 20 ActivityManagerNative#broadcastIntent :1084行目 public int broadcastIntent(IApplicationThread caller, ・・・) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null); data.writeInt(resultCode); data.writeString(resultData); data.writeBundle(map); data.writeString(requiredPermission); data.writeInt(serialized ? 1 : 0); data.writeInt(sticky ? 1 : 0); mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); reply.recycle(); data.recycle(); return res; } ©Japan Android Group, 2008 21 結局のところ オブジェクトをマーシャル、アンマーシャルし て渡す仕組みだろう よくあるプロセス間通信の実装方式 Parcelからオブジェクトを出し入れしているだけ public static Parcel obtain() { final Parcel[] pool = sOwnedPool; synchronized (pool) { Parcel p; for (int i=0; i<POOL_SIZE; i++) { p = pool[i]; if (p != null) { pool[i] = null; if (DEBUG_RECYCLE) { p.mStack = new RuntimeException(); } return p; } } } return new Parcel(0); } Parcelのobtainメソッド: 235行目 ©Japan Android Group, 2008 22 結局のところ mRemoteは、android.os.IBinder ServiceのときにBinderを実装すると思うが、それ と同じノリ。Serviceを使えば理解が深まる。 Binderのtransactメソッドは同期 Parcelにマーシャルしたものを置くだけ broadcastでもアプリ側に制御はすぐ返ってくる BinderやParcelの中身や振る舞いをちゃんと 理解すれば、腑に落ちると思う ©Japan Android Group, 2008 23
© Copyright 2024 ExpyDoc