我正在尝试在Xamarin.Droid中使用后台服务(使用mvvmcross),该服务在登录后启动。 假设它应该每3个小时运行一次,即使应用程序被taskmanager杀死了。
由于服务执行的任务(获取gps位置,然后向服务器发送post请求)需要用户进行身份验证(通过令牌),因此只有在承载令牌有效时才应运行该任务。 基本上我希望它一直运行,除非我还没有登录,或者当我退出时。
下面,我的代码在https://technology.jana.com/2014/10/28/periodic-background-tasks-in-android/
的Java示例后面找到的Manifest.xml
<receiver android:name="com.livelakecomo.PeriodicTaskReceiver">
<intent-filter>
<action android:name="android.intent.action.BATTERY_LOW" />
<action android:name="android.intent.action.BATTERY_OKAY" />
<action android:name="live.xam.lakecomo.droid.PERIODIC_TASK_HEART_BEAT" />
</intent-filter>
</receiver>
<receiver android:name="com.livelakecomo.BootAndUpdateReceiver">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.livelakecomo.BackgroundService" />
BootAndUpdateReceiver.cs
using Android.Content;
using Android.Util;
namespace Live.Xam.LakeComo.Droid
{
[BroadcastReceiver(Name = "com.livelakecomo.BootAndUpdateReceiver")]
public class BootAndUpdateReceiver : BroadcastReceiver
{
private static string TAG = "BootAndUpdateReceiver";
public override void OnReceive(Context context, Intent intent)
{
Log.Info(TAG, "Booted");
System.Diagnostics.Debug.WriteLine("boot onreceive");
if (intent.Action.Equals("android.intent.action.BOOT_COMPLETED") ||
intent.Action.Equals("android.intent.action.MY_PACKAGE_REPLACED")) {
Intent startServiceIntent = new Intent(context, typeof(BackgroundService));
context.StartService(startServiceIntent);
}
}
}
}
BackgroundService
using Android.App;
using Android.Content;
using Android.OS;
using Android.Util;
using Live.Base.Xam.Core;
using Plugin.CurrentActivity;
namespace Live.Xam.LakeComo.Droid
{
public class BackgroundBinder : Binder
{
BackgroundService service;
public BackgroundBinder(BackgroundService service)
{
this.service = service;
}
}
public class BackgroundService : Service
{
BackgroundBinder binder;
private static string TAG = "BackgroundService";
PeriodicTaskReceiver mPeriodicTaskReceiver = new PeriodicTaskReceiver();
public override IBinder OnBind(Intent intent)
{
binder = new BackgroundBinder(this);
return binder;
}
public int OnStartCommand(Intent intent, int flags, int startId)
{
Log.Info(TAG, "OnstartCommand");
MainApplication myApplication = (MainApplication)CrossCurrentActivity.Current.Activity.Application;
ISharedPreferences sharedPreferences = myApplication.GetSharedPreferences("sharedprefs", FileCreationMode.WorldWriteable);
IntentFilter batteryStatusIntentFilter = new IntentFilter(Intent.ActionBatteryChanged);
Intent batteryStatusIntent = RegisterReceiver(null, batteryStatusIntentFilter);
if (batteryStatusIntent != null)
{
int level = batteryStatusIntent.GetIntExtra(BatteryManager.ExtraLevel, -1);
int scale = batteryStatusIntent.GetIntExtra(BatteryManager.ExtraScale, -1);
float batteryPercentage = level / (float)scale;
float lowBatteryPercentageLevel = 0.14f;
try
{
int lowBatteryLevel = Resources.GetInteger(Resources.GetIdentifier("config_lowBatteryWarningLevel", "integer", "android"));
lowBatteryPercentageLevel = lowBatteryLevel / (float)scale;
}
catch (Android.Content.Res.Resources.NotFoundException e)
{
Android.Util.Log.Error(TAG, "Missing low battery threshold resource");
}
sharedPreferences.Edit().PutBoolean(LiveConstants.BACKGROUND_SERVICE_BATTERY_CONTROL, batteryPercentage >= lowBatteryPercentageLevel).Apply();
}
else
{
sharedPreferences.Edit().PutBoolean(LiveConstants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).Apply();
}
mPeriodicTaskReceiver.RestartPeriodicTaskHeartBeat(ApplicationContext, myApplication);
return (int)StartCommandResult.RedeliverIntent;
}
}
}
PeriodicTaskReceiver
using Android.Content;
using Android.Preferences;
using Android.App;
using Plugin.CurrentActivity;
using Android.OS;
using Live.Base.Xam.Core;
using System;
using Android.Locations;
using Android.Runtime;
using Android.Util;
using System.Threading.Tasks;
using Live.Base.Xam.Core.Services;
namespace Live.Xam.LakeComo.Droid
{
[BroadcastReceiver(Name = "com.livelakecomo.PeriodicTaskReceiver")]
public class PeriodicTaskReceiver : BroadcastReceiver, ILocationListener
{
private static string TAG = "PeriodicTaskReceiver";
private static string INTENT_ACTION = "com.livelakecomo.PERIODIC_TASK_HEART_BEAT";
private LocationManager _locationManager;
private string _locationProvider;
private Location _currentLocation;
public override void OnReceive(Context context, Intent intent)
{
Log.Info("robbyPeriodic", "OnReceive");
System.Diagnostics.Debug.WriteLine("robbysbobby OnReceive");
var myApplication = (MainApplication)CrossCurrentActivity.Current.Activity.Application;
if (!string.IsNullOrEmpty(intent.Action))
{
ISharedPreferences sharedPreferences = PreferenceManager.GetDefaultSharedPreferences(CrossCurrentActivity.Current.Activity.ApplicationContext);
if (intent.Action.Equals("android.intent.action.BATTERY_LOW"))
{
sharedPreferences.Edit().PutBoolean(LiveConstants.BACKGROUND_SERVICE_BATTERY_CONTROL, false).Apply();
StopPeriodicTaskHeartBeat(context);
}
else if (intent.Action.Equals("android.intent.action.BATTERY_OKAY"))
{
sharedPreferences.Edit().PutBoolean(LiveConstants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).Apply();
RestartPeriodicTaskHeartBeat(context, myApplication);
}
else if (intent.Action.Equals(INTENT_ACTION))
{
DoPeriodicTask(context, myApplication);
}
}
}
private void DoPeriodicTask(Context context, MainApplication myApplication)
{
System.Diagnostics.Debug.WriteLine("robbysbobby DoPeriodicTask");
Log.Info("robbyPeriodic", "DoPeriodic");
InitializeLocationManager();
System.Threading.Tasks.Task.Run(async () => { await SendInformationToServer(); }).Wait();
}
private async Task<bool> SendInformationToServer()
{
Log.Info("robbyPeriodic", "Dentro Sendnotify");
System.Diagnostics.Debug.WriteLine("robbysbobby sendnotify");
//if (_currentLocation == null)
// return false;
var geo = Plugin.Geolocator.CrossGeolocator.Current;
if (geo.IsGeolocationAvailable && geo.IsGeolocationEnabled)
{
try
{
var position = await geo.GetPositionAsync(timeoutMilliseconds: LiveConstants.GpsTimeout);
await CommunicationService.Instance.UpdateUserLocation(position.Latitude, position.Longitude);
return true;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.StackTrace);
//no position
}
}
return false;
}
public void RestartPeriodicTaskHeartBeat(Context context, MainApplication myApplication)
{
ISharedPreferences sharedPreferences = myApplication.GetSharedPreferences("sharedprefs", FileCreationMode.WorldWriteable);
bool isBatteryOk = sharedPreferences.GetBoolean(LiveConstants.BACKGROUND_SERVICE_BATTERY_CONTROL, true);
Intent alarmIntent = new Intent(context, typeof(PeriodicTaskReceiver));
bool isAlarmUp = PendingIntent.GetBroadcast(context, 0, alarmIntent, PendingIntentFlags.NoCreate) != null;
if (isBatteryOk && !isAlarmUp)
{
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarmIntent.SetAction(INTENT_ACTION);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
alarmManager.SetInexactRepeating(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime(), 15 * 1000 , pendingIntent);
}
}
public void StopPeriodicTaskHeartBeat(Context context)
{
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
Intent alarmIntent = new Intent(context, typeof(PeriodicTaskReceiver));
alarmIntent.SetAction(INTENT_ACTION);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
alarmManager.Cancel(pendingIntent);
}
}
}
在LoginViewmodel中
Mvx.Resolve<IBackgroundService>().StartBackgroundService();
调用droid实现
public void StartBackgroundService()
{
Intent startServiceIntent = new Intent(CrossCurrentActivity.Current.Activity.ApplicationContext, typeof(BackgroundService));
CrossCurrentActivity.Current.Activity.StartService(startServiceIntent);
Log.Info("BGService", "Started Background Service");
System.Diagnostics.Debug.WriteLine("Started Background Service");
}
PS:我读了很多文章,但我不确定在actoin / receiver名称中我是否必须在类名之前放入包名或命名空间(小写)。
截至目前,我得到的是启动服务被调用,但我没有看到任何logcat写任何东西,所以它就像没有接收器或服务实际上开始做某事。 我做错了什么?
感谢您的帮助!!!