java - Android 广播接收器没有接收到显式广播?

标签 java android

我正在尝试为我正在使用的 Android 应用程序添加后台服务。我关注了this guide用于添加服务并在主 Activity 被销毁时让它在后台重新启动。这没有像指南中显示的那样工作,因为(我认为)我需要使广播明确(描述 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>

最佳答案

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

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

关于java - Android 广播接收器没有接收到显式广播?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52102868/

相关文章:

java - 我如何在 android studio -Java 中仅选择 3 个选项 RadioButton 或订单

java - Jooq 错误 : missing FROM-clause entry for table for nested query(sum and group by)

java - 使用java从文件中读取日期

java - Android ActionBar - 项目图标不断变化?

Android Activity Intent 在关机后仍然存在

android - AndroidX AppCompat 包的 Proguard 规则

java - 从 HandlerInterceptor 抛出 HTTP 状态代码异常

java - 2段代码有什么区别?

android - 如何在 ADT 项目中使用 ffmpeg4android?

android - 从 Activity Kotlin 中获取额外的字符串