我正在尝试向正在使用的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>
答案 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);