Когда использовать какой конструктор для ComponentName в Android? - PullRequest
25 голосов
/ 13 февраля 2011

Я немного запутался в классе ComponentName в Android.

Существуют разные способы добраться до объекта имени компонента, но я не знаю, когда использовать какой ... и почему!

Пример:

  • Пакет приложения 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 - по контексту и по строке.Какой из них следует использовать, где и когда ??

Спасибо!

Ответы [ 3 ]

41 голосов
/ 13 февраля 2011

Конструктор ComponentName, принимающий два String с, может использоваться для ссылки на компонент в другом приложении. Но первый аргумент не является именем пакета класса; это имя пакета приложения --- атрибут package элемента manifest в AndroidManifest.xml этого приложения. Итак, ваш первый пример должен быть

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

Этот конструктор, безусловно, может использоваться для ссылки на компоненты в вашем собственном приложении, но, поскольку у вас уже есть Context из вашего собственного приложения, вы также можете использовать его и использовать один из других конструкторов. На мой взгляд, тот, кто принимает Class, должен быть предпочтительным при использовании. Вы можете использовать тот, который принимает String, если по какой-то причине вы знаете класс только динамически; в этом случае оно должно принимать полное имя класса, как указано выше.

3 голосов
/ 19 июня 2016

Роберт Тупело-Шнек правильно ответил о том, что предпочитает объекты строкам. Вот как я это вижу.

  • Чтобы сослаться на свои собственные компоненты, используйте:

    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="

Здесь может быть некоторая путаница, потому что я думаю, что исторически утверждение Роберта было правдой:

это имя пакета приложения --- атрибут пакета элемента manifest в AndroidManifest.xml этого приложения

но не больше. С момента появления новой системы сборки Gradle здесь произошли некоторые изменения .

Если в build.gradle указано android.defaultConfig.applicationId, это будет имя пакета приложения, а затем атрибут package в манифесте - это отдельная вещь при создании приложения. Первый аргумент ComponentName теперь относится к applicationId + applicationIdSuffix. Хитрость заключается в том, что после окончательного слияния и упаковки манифеста APK будет иметь <manifest package=applicationId + applicationIdSuffix, и все .Names будут расширены до FQCN.

Пример приложения для обучения разрешению имен

Вот пример структуры, основанной на структуре одного из моих приложений. Рассмотрим следующие классы в гипотетическом приложении под названием «приложение»:

  • 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 голосов
/ 14 февраля 2012

Или вы можете использовать вот так внутри BroadcastReceiver:

ComponentName smsReceiver = new ComponentName(this, SMSReceiver.class);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...