Android广播接收器没有收到明确的广播?

时间:2018-08-30 17:55:08

标签: java android

我正在尝试向正在使用的Android应用添加后台服务。我跟随this guide添加了服务,并在主要活动被破坏时在后台重新启动了服务。如指南中所示,这没有用,因为(我认为)我需要明确广播(描述here)。我试图通过将其添加到服务的构造函数中来做到这一点:

applicationContext.registerReceiver(
    new LocationSyncServiceRestarterBroadcastReceiver(),
    new IntentFilter("com.company.AppName.RestartLocationSyncService")
);

添加此内容后,当我关闭该应用程序时,它不再引发失败的广播错误,但它似乎也没有运行LocationSyncServiceRestarterBroadcastReceiver.onReceive(或者只是没有显示在日志中)。

这是我(从MainActivity内部)创建后台服务的方式:

private void startLocationSyncService() {
  ctx = this;
  mLocationSyncService = new LocationSyncService(getCtx());
  mLocationSyncServiceIntent = new Intent(getCtx(), mLocationSyncService.getClass());
  if (!isServiceRunning(mLocationSyncService.getClass())) {
    startService(mLocationSyncServiceIntent);
  }
}

private boolean isServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            Log.i ("isMyServiceRunning?", true+"");
            return true;
        }
    }
    Log.i ("isMyServiceRunning?", false+"");
    return false;
}

这是我的后台服务:

package com.company.AppName;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

public class LocationSyncService extends Service {
  private static final String TAG = "LocationSyncService";
  private LocationManager mLocationManager = null;
  private static final int LOCATION_INTERVAL = 1000;
  private static final float LOCATION_DISTANCE = 10f;

  LocationListener[] mLocationListeners = new LocationListener[] {
      new LocationListener(LocationManager.GPS_PROVIDER),
      new LocationListener(LocationManager.NETWORK_PROVIDER)
  };

  public LocationSyncService() {}
  public LocationSyncService(Context applicationContext) {
    super();
    Log.i(TAG, "created");
    applicationContext.registerReceiver(
        new LocationSyncServiceRestarterBroadcastReceiver(),
        new IntentFilter("com.company.AppName.RestartLocationSyncService")
    );
  }

  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    Log.i(TAG, "onBind");
    return null;
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    Log.i(TAG, "onStartCommand");
    return START_STICKY;
  }

  @Override
  public void onCreate()
  {
    Log.e(TAG, "onCreate");
    initializeLocationManager();
    try {
      mLocationManager.requestLocationUpdates(
          LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
          mLocationListeners[1]);
    } catch (java.lang.SecurityException ex) {
      Log.e(TAG, "fail to request location update, ignore", ex);
    } catch (IllegalArgumentException ex) {
      Log.e(TAG, "network provider does not exist, " + ex.getMessage());
    }
    try {
      mLocationManager.requestLocationUpdates(
          LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
          mLocationListeners[0]);
    } catch (java.lang.SecurityException ex) {
      Log.e(TAG, "fail to request location update, ignore", ex);
    } catch (IllegalArgumentException ex) {
      Log.e(TAG, "gps provider does not exist " + ex.getMessage());
    }
  }

  private void initializeLocationManager() {
    Log.i(TAG, "initializeLocationManager");
    if (mLocationManager == null) {
      mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    }
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "onDestroy");
    Intent broadcastIntent = new Intent("com.company.AppName.RestartLocationSyncService");
    sendBroadcast(broadcastIntent);
  }

  private class LocationListener implements android.location.LocationListener
  {
    Location mLastLocation;

    public LocationListener(String provider)
    {
      Log.i(TAG, "LocationListener " + provider);
      mLastLocation = new Location(provider);
    }

    @Override
    public void onLocationChanged(Location location)
    {
      Log.i(TAG, "onLocationChanged: " + location);
      mLastLocation.set(location);
    }

    @Override
    public void onProviderDisabled(String provider)
    {
      Log.i(TAG, "onProviderDisabled: " + provider);
    }

    @Override
    public void onProviderEnabled(String provider)
    {
      Log.i(TAG, "onProviderEnabled: " + provider);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras)
    {
      Log.i(TAG, "onStatusChanged: " + provider);
    }
  }
}

以及应该重新启动服务的广播接收器:

package com.company.AppName;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class LocationSyncServiceRestarterBroadcastReceiver extends BroadcastReceiver {
  private static final String TAG = "RestarterBcastReceiver";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.i(TAG, "----- onReceive!!!");
    context.startService(new Intent(context, LocationSyncService.class));
  }
}

还有我的AndroidManifest.xml

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="10000" android:versionName="1.0.0" package="com.company.AppName" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
        </provider>
        <service android:enabled="true" android:name="com.company.AppName.LocationSyncService" />
        <receiver android:enabled="true" android:exported="true" android:label="RestartLocationSyncServiceWhenStopped" android:name="com.company.AppName.LocationSyncServiceRestarterBroadcastReceiver">
            <intent-filter>
                <action android:name="com.company.AppName.RestartLocationSyncService" />
            </intent-filter>
        </receiver>
    </application>
    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="26" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

3 个答案:

答案 0 :(得分:1)

解决方案是调用从服务的setComponent方法发送到广播接收器的意图上的onDestroy

@Override
public void onDestroy() {
  super.onDestroy();
  Intent broadcastIntent = new Intent("com.company.AppName.RestartLocationSyncService");
  broadcastIntent.setComponent(new ComponentName("com.company.AppName", "com.company.AppName.LocationSyncServiceRestarterBroadcastReceiver"));
  sendBroadcast(broadcastIntent);
}

答案 1 :(得分:0)

如果您无法发送隐式广播或隐式意图,请首先检查ComponentName。包名称必须是应用程序ID,而不是您在接收器类中可以看到的包名称。

在build.gradle中查找应用程序ID:

             defaultConfig {
                            applicationId "com.my.app.id.name"

或在构建后自动生成的buildConfig.java文件中:

app \ build \ generate \ source \ buildConfig \ release \

             package com.my.app.id.name;

例如,如果您的班级名称是“ MyExplicitReciver” 在类的第一行中看到的包名称是

            package com.my.app.myPackage.name.receivers;

所以类名应该是:                  com.my.app.myPackage.name.receivers.MyExplicitReciver

,您应该在setComponent中设置这样的名称:

            intent.setComponent(new ComponentName("com.my.app.id.name",
    "com.my.app.myPackage.name.receivers"));
            context().sendBroadcast(intent);

答案 2 :(得分:0)

更简单的方法。

Intent intent = new Intent("TEST");
intent.setPackage( getPackageName() );
sendBroadcast(intent);