何时在Android中使用ComponentName的构造函数?

时间:2011-02-13 18:02:39

标签: android constructor components

我对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的方法 - 按上下文和字符串。 应该在何时何地使用哪一个?

谢谢!

3 个答案:

答案 0 :(得分:41)

使用两个ComponentName的{​​{1}}构造函数可用于引用另一个应用程序中的组件。但是,第一个参数不是类的包名;它是应用程序的包名称---该应用程序Stringpackage元素的manifest属性。所以你的第一个例子应该是

AndroidManifest.xml

该构造函数当然可以用于引用您自己的应用程序中的组件,但由于您已经拥有自己的应用程序中的ComponentName cn = new ComponentName("de.zordid.sampleapp", "de.zordid.sampleapp.widget.WidgetProvider"); ,因此您可以使用它并使用其他构造函数之一。在我看来,只要可以使用,Context的人应该是首选。如果您因某种原因仅动态地知道该类,则可以使用Class的那个;在这种情况下,它应该采用上面的完全限定类名。

答案 1 :(得分:3)

或者你可以在BroadcastReceiver中使用这样的东西:

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

答案 2 :(得分:3)

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中的清单元素的包属性

但不再是。自从引入新的Gradle构建系统以来,这里已经有some changes

如果您的android.defaultConfig.applicationId中指定了build.gradle该应用包名称,那么构建应用时,清单中的package属性就是一个单独的内容。 ComponentName的第一个参数现在引用applicationId + applicationIdSuffix。棘手的是,在最终清单合并和打包后,APK将有<manifest package=applicationId + applicationIdSuffix,所有.Names将扩展为FQCN。

学习名称解析的示例应用

这是一个基于我的某个应用程序结构的示例结构。在名为&#34; app&#34;:

的假设应用中考虑以下类
  • 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中命名。安卓应用程序只是整个内部的一部分自己的子包。

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后查看最终清单的样子。