この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
概要
突然ですが、 Android に対して通知を発行するため等に使用する PendingIntent は、その一意性を Intent の一意性をもって定義しています。
このように、 Android 開発を行っていると何かと出くわすことの多い Intent が同一かどうかの判定 について解説します。
注: 実際には、 PendingIntent は IIntentSender を見ていて、そこに設定されている requestCode も一意性に含まれるのですが、ちょっと深く入りすぎるのでここでは"Intent を見ている"とさせて下さい。
Intent の同一性は Intent.filterEquals で確認される
ふたつの Intent が同一なものかどうか確認する際には、その確認元( AndroidSDK や OSS )によって Intent.filterEquals が呼びだされます。
このメソッドの定義および実装は次のとおりです。
public boolean filterEquals(Intent other) {
if (other == null) {
return false;
}
if (mAction != other.mAction) {
if (mAction != null) {
if (!mAction.equals(other.mAction)) {
return false;
}
} else {
if (!other.mAction.equals(mAction)) {
return false;
}
}
}
if (mData != other.mData) {
if (mData != null) {
if (!mData.equals(other.mData)) {
return false;
}
} else {
if (!other.mData.equals(mData)) {
return false;
}
}
}
if (mType != other.mType) {
if (mType != null) {
if (!mType.equals(other.mType)) {
return false;
}
} else {
if (!other.mType.equals(mType)) {
return false;
}
}
}
if (mPackage != other.mPackage) {
if (mPackage != null) {
if (!mPackage.equals(other.mPackage)) {
return false;
}
} else {
if (!other.mPackage.equals(mPackage)) {
return false;
}
}
}
if (mComponent != other.mComponent) {
if (mComponent != null) {
if (!mComponent.equals(other.mComponent)) {
return false;
}
} else {
if (!other.mComponent.equals(mComponent)) {
return false;
}
}
}
if (mCategories != other.mCategories) {
if (mCategories != null) {
if (!mCategories.equals(other.mCategories)) {
return false;
}
} else {
if (!other.mCategories.equals(mCategories)) {
return false;
}
}
}
return true;
}
上記から、 Intent の一意性は次の要素によって定まっていることがわかります。
- mAction (setAction メソッドで設定できる String プロパティ)
- mData (setData メソッドで設定できる Uri プロパティ)
- mType (setType メソッドで設定できる String プロパティ)
- mPackage (setPackage メソッドで設定できる String プロパティ)
- mComponent (setComponent や、よく使用されるコンストラクタ で設定できる、 ComponentName プロパティ)※詳細は後述
- mCategories (addCategory メソッドで追加できる、Stringのセット)
このうち、とりわけ重要な要素となっているのが、 mComponent プロパティです。
まずは、 Intent クラスに定義された次のコンストラクタ定義を確認してください。
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
これは、私たちが普段 Intent intent = new Intent(this, MyReallyCoolActiviy.class); といった具合に使用しているコンストラクタです。
上記のコンストラクタでは、 mComponent 以外の値が設定されていないことがわかります。
つまり、 私たちが別途 intent.setAction("MY_AWESOME_ACTION"); や intent.setData(Uri.parse("custom:uri")); のような設定をしない限りは、次の2つの Intent は同一です:
Intent myAwesomeIntent = new Intent(this, HogeActivity.class);
Intent myCoolIntent = new Intent(this, HogeActivity.class);
Log.d(TAG, "filterEquals: " + myAwesomeIntent.filterEquals(myCoolIntent)); // -> true
そして、上述の仕様を把握すれば、 Intent に任意の一意性を持たせることが出来ます。
Intent に任意の一意性を付加する
概要で説明したとおり、 Android 開発では何かと Intent が同じかどうかが問題になることがあります。
一例ですが、通常のアクティビティ呼び出しや、サービス呼び出しに使用する Intent にであれば、次のように任意に一意性を与えることが出来ます。
public static Intent createIntentWithId(String intentId) {
Intent intent = new Intent(this, HogeActiviy.class);
intent.setData(Uri.parse("myApp://intentId/" + intentId));
return intent;
}
(前述のとおり)上の例で使用しているコンストラクタは mComponent のみを設定します。よって、他の項目については私たちが設定できます。
上の例では、 mData に値を設定することで一意性を付加しています。
setType(String type) メソッドは、 mType
を設定するだけでなく、 mData に null を設定します。このメソッド使用する際には注意してください。
まとめ
Intent の filterEquals の仕様を理解して、うまく Intent を管理しましょう。