【问题标题】:ApplicationContext in BroadcastReceiver广播接收器中的应用程序上下文
【发布时间】:2016-12-09 13:10:40
【问题描述】:

我有一个这样的应用程序类:

public class MyApplication extends Application {
}

在Manifest中注册:

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    ... 

    </application>

我使用这个 Application 类来保存 Dagger 组件等。

现在我有一个广播接收器:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent){

       MyApplication myApplication = (MyApplication) context.getApplicationContext();           
    }
}

它在 Manifest 中注册为InstallReferrerReceiver:

    <receiver
        android:name="my.package.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="com.android.vending.INSTALL_REFERRER"/>
        </intent-filter>
    </receiver>

如您所见,我将应用程序上下文转换为我的应用程序类,它在活动等中运行良好,通常也在这里。

虽然我收到异常,但通过 Crashlytics:

Unable to start receiver my.package.BroadcastReceiver: java.lang.ClassCastException: android.app.Application cannot be cast to my.package.MyApplication

我的问题是:我是否不保证接收我的应用程序对象作为广播接收器中的应用程序上下文?

【问题讨论】:

  • 应该可以的。报告此崩溃的设备之间是否有任何共性?此外,&lt;receiver&gt; 元素(例如,您使用的是android:process)或广播的发送方式是否有任何异常?
  • 我认为不能保证您可以在BroadcastReceiver 中访问您的应用程序(我正在寻找源代码)。你能查一下if (context.getApplicationContext() instanceof MyApplication)吗?
  • @CommonsWare 抱歉,这可能很重要,我已经为接收者添加了清单条目。
  • @ThomasRoulin 是的,我当然可以检查,但最终我需要以某种方式保证拥有 my 应用程序,否则我必须解决这个问题。跨度>
  • &lt;receiver&gt; 看起来又好又无聊。 :-) AFAIK,你应该得到一个MyApplication。自己测试一下(例如,使用adb shell am 发送匹配的广播),看看它是否有效。如果确实如此,请再次查找报告此崩溃的设备的共性。

标签: android broadcastreceiver android-context


【解决方案1】:

如果您查看 ActivityThread.handleReceiver 的实现,您会发现 BroadcastReceiver.onReceived 是通过将 ContextImpl.getReceiverRestrictedContext() 传递给它来调用的。此调用返回的上下文实际上并未包装 getApplicationContext,因此将在 ContextImpl 上调用 ti。现在,如果您查看 ContextImpl.getApplicationContext(),您会看到类似这样的内容

@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ? mPackageInfo.getApplication() : 
        mMainThread.getApplication();
}

如果您查看三元运算符的最后一个分支,您会发现它将回调到 ActivityThread.getApplication(),这将返回它的 mInitialApplication 成员。 mInitialApplication 是通过调用 LoadedApk.makeApplication() 来初始化的,它有一个布尔参数:forceDefaultAppClass。如果设置为 true android.app.Application 将实例化而不是在清单中定义的应用程序。

根据 AOSP 来源,这发生在例如:

如果正在启动应用程序以进行完整备份或恢复,请将其启动 在具有基本应用程序类的受限环境中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多