home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

技術/Android/AmbiguousDocuments

技術/Android/AmbiguousDocuments

技術 / Android / AmbiguousDocuments
id: 996 所有者: msakamoto-sf    作成日: 2011-07-10 14:04:40
カテゴリ: Android 

ドキュメントが曖昧で間違えやすい箇所のメモ。


AndroidManifest.xml関連

<activity>の"android:name"属性

例:

<manifest>の"package"属性 foo.bar
ActivityクラスのFQCN(Fully Qualified Class Name) foo.bar.activities.ActivityX

この時、<activity>の"android:name"属性でActivityXを指定したい時の正誤パターン。

正:
<activity android:name=".activities.ActivityX"></activity>

誤:
<activity android:name="foo.bar.activities.ActivityX"></activity>
<activity android:name="activities.ActivityX"></activity>
<activity android:name=".ActivityX"></activity>
<activity android:name="ActivityX"></activity>

説明:
"android:name"属性は、"."から始める場合はpackage部分を省略した表記として解釈される。
従ってpackageが"foo.bar"なら、"foo.bar.activities.ActivityX"からpackageを除去した".activities.ActivityX"を指定する。
それ以外は全て間違って解釈される。

Activityのクラスがpackageの直下にあるのなら、".クラス名"にすればよい。
例:

"foo.bar.Main" → <activity android:name=".Main">

間違えやすい背景:
Androidの公式ドキュメントに出てくる"package名"の殆どは AndroidManifest.xml の"<manifest>"の"package"属性で指定した値を指している。
Javaのクラス名で扱う"package"で考えると、ズレが生じて間違える元になる。
例えばActivityに指定したいクラスが"foo.bar.baz.Main"とすれば、Javaの世界での"package"は"foo.bar.baz"となる。しかし<manifest>のpackage属性で"foo.bar"が指定されていれば、Androidアプリの世界での"package名"は"foo.bar"となる。

公式ドキュメント上での説明:

<permission>の"android:name"属性

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="foo.bar"
      android:versionCode="1"
      android:versionName="1.0">

この場合、"<permission>"の"android:name"属性もpackageで始める。

正:
<permission ... android:name="foo.bar.PERM_X" ...>
誤:
<permission ... android:name="PERM_X" ...>

説明:
公式ドキュメントには

The name must be unique, so itshoulduse Java-style scoping

とあり、MUSTとは書かれていない。このため、タイピング数を少なくしようとpackage名を省略すると、SecurityExceptionの発生に頭を悩ませることになる。

将来的に実装がどう変わるのか不明なので、本記事で"MUST"と断言することは出来ない。ただし、実際にトラブルが発生したことは確かなので、package名で始めることを推奨しておく。

明示的Intentでのパッケージ名、クラス名

URIではなく、直接パッケージ名とクラス名を指定してIntentを使いたい場合:

Intent i = new Intent();
i.setClassName(String packageName, String className)

例:package="foo.bar" アプリの、FQCN="foo.bar.activities.Main"を指定する。

正:
i.setClassName("foo.bar", "foo.bar.activities.Main");

誤:
i.setClassName("foo.bar", ".activities.Main");
i.setClassName("foo.bar.activities", ".Main");
i.setClassName("foo.bar.activities", "Main");

説明:
IntentのsetClassName(String packageName, String className)は

public ComponentName (String pkg, String cls)

のショートカットとなっている。ここで"packageName", "pkg"は当然<manifest>の"package"属性を指定する。ここをJavaクラスのパッケージと勘違いしたのが、

i.setClassName("foo.bar.activities", ".Main");
i.setClassName("foo.bar.activities", "Main");

と指定したパターン。

問題は"className", "cls"の部分で、公式ドキュメントにも

cls The name of the class inside of pkg that implements the component. Can not be null.

としか書かれておらず、FQCNを指定すればよいのかが曖昧なままになっている。
ここで<activity>の"android:name"属性と同様と勘違いしてしまうパターンが次のケース。

i.setClassName("foo.bar", ".activities.Main");

結論から言うとFQCNを指定する必要がある。

ヒントとなるのが

public ComponentName (Context pkg, Class<?> cls)

というコンストラクタの存在であり、"Class"のgetName()メソッドはFQCN表記を返す。このことから、Stringで指定する場合もFQCNとなることが予想できる。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2011-07-10 14:05:41
md5:ee88f2e58642867127cbad1ca2ae249a
sha1:f3ebd9ec246f77bad6020d5772381fcbdbadcbd4
コメント
コメントを投稿するにはログインして下さい。