web-dev-qa-db-ja.com

AndroidでComponentNameにどのコンストラクターを使用するのですか?

AndroidのComponentNameクラスについて少し混乱しています。

コンポーネント名オブジェクトを取得する方法はいくつかありますが、いつどのように使用すればよいのかわかりません。なぜですか!

例:

  • アプリケーションパッケージはde.zordid.sampleapp
  • ウィジェットプロバイダークラスはde.zordid.sampleapp.widget.WidgetProvider

使用する

ComponentName cn = new ComponentName("de.zordid.sampleapp.widget",
    "WidgetProvider");

このコンポーネント情報を取得しました:ComponentInfo{de.zordid.sampleapp.widget/WidgetProvider}、しかしこれは使用できませんでした-コンポーネントは不明です!しかし、JavaDocは、パッケージとそのパッケージ内のクラスを与えるべきだと言っています-そしてそれは私がやったことではありませんか?

使用する

ComponentName cn = new ComponentName(context, WidgetProvider.class);

ComponentInfo{de.zordid.sampleapp/de.zordid.sampleapp.widget.WidgetProvider}-そしてそれはうまくいきます!!

ComponentNameを取得するには、コンテキストと文字列による別の方法もあります。どこで、いつ使用するのですか?

ありがとう!

31
Zordid

2つのComponentNamesを取るStringコンストラクターを使用して、別のアプリケーションのコンポーネントを参照できます。ただし、最初の引数はクラスのパッケージ名ではありません。これは、アプリケーションのパッケージ名、つまりそのアプリケーションのAndroidManifest.xmlpackage要素のmanifest属性です。だからあなたの最初の例は

ComponentName cn = new ComponentName("de.zordid.sampleapp",
    "de.zordid.sampleapp.widget.WidgetProvider");

そのコンストラクターは確かに独自のアプリケーションのコンポーネントを参照するために使用できますが、独自のアプリケーションからのContextをすでに保持しているので、それを使用して他のコンストラクターの1つを使用することもできます。私の意見では、Classを使用する方が、使用可能であればいつでも優先する必要があります。何らかの理由でクラスを動的に知っているだけなら、Stringを取るものを使用できます。その場合は、上記の完全修飾クラス名を使用する必要があります。

42

または、BroadcastReceiver内で次のように使用できます。

ComponentName smsReceiver = new ComponentName(this, SMSReceiver.class);
3
Jviaches

Robert Tupelo-Schneck の答えは、文字列ではなくオブジェクトを優先することです。これが私の見方です。

  • 独自のコンポーネントを参照するには、以下を使用します。

    new ComponentName(getApplicationContext(), WidgetProvider.class);
    
  • 独自のアプリで動的に参照されるコンポーネントを参照するには、次を使用します。

    // values/strings.xml: <string name="provider">de.zordid.sampleapp.widget.WidgetProvider</string>
    String fqcn = getResources().getString(R.string.provider);
    new ComponentName(getApplicationContext(), fqcn);
    

    これは、Androidのリソース修飾子を使用して、使用するコンポーネントを決定する場合に役立ちます。values-*/strings.xmlのデフォルトの文字列をオーバーライドできます。

  • 別のアプリケーションのコンポーネントを参照するには、次を使用します。

    int componentFlags = GET_ACTIVITIES | GET_PROVIDERS | GET_RECEIVERS | GET_SERVICES;
    PackageInfo otherApp = context.getPackageManager().getPackageInfo("com.other.app", componentFlags);
    ComponentInfo info = otherApp.activities[i]; // or providers/receivers/...
    new ComponentName(info.packageName, info.name);
    

.Namesと<manifest package="について

歴史的にロバートの発言は真実だったと思うので、ここで混乱が生じるかもしれません。

これはアプリケーションのパッケージ名です---そのアプリケーションのAndroidManifest.xmlのmanifest要素のpackage属性です

もうそうじゃない。新しいGradleビルドシステムが導入されてから、ここに いくつかの変更 がありました。

Android.defaultConfig.applicationIdbuild.gradleが指定されている場合、それがアプリパッケージ名となり、マニフェストのpackage属性は、アプリのビルド時に別のものになります。 ComponentNameの最初の引数はapplicationId + applicationIdSuffixを参照するようになりました。トリッキーなことは、最終的なマニフェストのマージとパッケージ化の後、APKは<manifest package=applicationId + applicationIdSuffixを持ち、すべての.NamesがFQCNに展開されることです。

名前解決を学習するためのアプリの例

これは、私のアプリの1つの構造に基づく構造の例です。 「app」と呼ばれる架空のアプリで、次のクラスを考えます。

  • net.twisterrob.app.Android.App
  • net.twisterrob.app.Android.GlideSetup
  • net.twisterrob.app.Android.subpackage.SearchResultsActivity
  • net.twisterrob.app.Android.subpackage.Activity
  • net.twisterrob.app.Android.content.AppProvider

アプリのサーバー側バックエンドまたは一部の共有モデルクラス、あるいはその両方で:

  • net.twisterrob.app.data.*
  • net.twisterrob.app.backend.*
  • net.twisterrob.app.web.*

私のAndroidヘルパーライブラリ:

  • net.twisterrob.Android.activity.AboutActivity

他のライブラリ:

  • Android.support.v4.content.FileProvider

このようにして、すべてがnet.twisterrob.appで名前空間になります。 Androidアプリは、独自のサブパッケージ内の全体の一部にすぎません。

AndroidManifest.xml(無関係な部分は省略)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
          package="net.twisterrob.app.Android">
    <!--
    `package` above defines the base package for .Names
    to simplify reading/writing the manifest.
    Notice that it's different than the `applicationId` in build.gradle
    and can be independently changed in case you want to refactor your packages.
    This way you can still publish the same app with the same name.
    -->

    <!-- Will be expanded to net.twisterrob.app.Android.App in the manifest merging phase. -->
    <application Android:name=".App">
        <!-- meta-data needs FQCNs because the merger can't know if you want to expand them or not.
             Also notice that name and value both can contain class names, depending on what you use. -->
        <meta-data Android:name="net.twisterrob.app.Android.GlideSetup" Android:value="GlideModule" />
        <meta-data Android:name="Android.app.default_searchable" Android:value="net.twisterrob.app.Android.subpackage.SearchResultsActivity" />
        <!-- Will be expanded to net.twisterrob.app.Android.subpackage.Activity in the manifest merging phase. -->
        <activity Android:name=".subpackage.Activity" />
        <!-- Needs full qualification because it's not under the package defined on manifest element. -->
        <activity Android:name="net.twisterrob.Android.activity.AboutActivity" />
        <!-- Will be expanded to net.twisterrob.app.Android.content.AppProvider in the manifest merging phase. -->
        <provider Android:name=".content.AppProvider" Android:authorities="${applicationId}" />
        <!-- Needs full qualification because it's not under the package defined on manifest element. -->
        <provider Android:name="Android.support.v4.content.FileProvider" Android:authorities="${applicationId}.share" />
    </application>
    <!-- ${applicationId} will be replaced with what's defined in `build.gradle` -->
</manifest>

build.gradle

Android {
    defaultConfig {
        // this is what will be used when you upload it to the Play Store
        applicationId 'net.twisterrob.app'
    }
    buildTypes {
        debug {
            // The neatest trick ever!
            // Released application: net.twisterrob.app
            // IDE built debug application: net.twisterrob.app.debug
            // This will allow you to have your installed released version
            // and sideloaded debug application at the same time working independently.
            // All the ContentProvider authorities within a system must have a unique name 
            // so using ${applicationId} as authority will result in having two different content providers.
            applicationIdSuffix '.debug'
        }
    }
}

マージ後の最終的なマニフェストがどのようになるかを確認するには、build\intermediates\manifests\full\debug\AndroidManifest.xmlを開きます。

3
TWiStErRob