Подтвердить что ты не робот

Когда использовать какой конструктор для ComponentName в Android?

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

Спасибо!

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

    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);
    

О именах и <manifest package="

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

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

но не больше. Поскольку новая система сборки Gradle была введена, здесь некоторые изменения.

Если у вас есть android.defaultConfig.applicationId, указанный в вашем build.gradle, который будет именем пакета приложения, а затем атрибут 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 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 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 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 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.