为了让我的服务发挥作用,我陷入了困境,我相信我刚刚进行了合并.我正在try 创建一个步进计数器服务,它使用一个处理器,该处理器上实现了一个步进计数器传感器.每6小时,我想用步数信息更新我的服务器,在接近一天结束时重置步数,并在我的处理程序上设置另一个alert ,以便每6小时执行相同的操作.处理程序还定期向活动发送数据,以读取其记录的步数.

然而,一切正常,但我无法在广播接收器中获得我的处理程序的实例.因此,永远不会设置另一个alert ,也永远不会重置步骤.有人能帮我吗?

具体来说,广播接收器(StepCounterHandler handler = StepCounterHandler.getInstance();)中的第一行代码在我的测试中总是返回null.

这是我的代码:

Android Manifest.xml:

    <receiver android:name=".Account.StepCounterService.StepCountUpdaterAlarm"
        android:exported="true">
    </receiver>

    <service
        android:enabled="true"
        android:process=":stepCounterService"
        android:name=".Account.StepCounterService.StepCounterService" />

StepCounterHandler.java:

public class StepCounterHandler extends Handler implements SensorEventListener {
private boolean onSensorChangedFirstCall = true;
private int previousSteps;
private int cumulativeSteps;

private List<String> debugInfo = new ArrayList<String>() {};

private static StepCounterHandler stepCounterHandler;

public static StepCounterHandler getInstance(Context callingContext, Looper looper) {
    if(stepCounterHandler == null) stepCounterHandler = new StepCounterHandler(callingContext, looper);
    Log.d("MyService", "setting handler instance:" + (stepCounterHandler == null));
    return stepCounterHandler;
}

public static StepCounterHandler getInstance()
{
    if(stepCounterHandler == null) return null;
    return stepCounterHandler;
}

private StepCounterHandler(Context callingContext, Looper looper) {
    super(looper);

    SensorManager sensorManager = (SensorManager) callingContext.getSystemService(Context.SENSOR_SERVICE);
    Sensor stepSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

    setAlarm(callingContext);

    if (stepSensor != null) {
        sensorManager.registerListener(this, stepSensor, SensorManager.SENSOR_DELAY_UI);
    } else {
        Toast.makeText(callingContext, "No step sensor has been detected on this device.", Toast.LENGTH_SHORT).show();
    }
}

public void setAlarm(Context context)
{
    AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

    Intent intent = new Intent(context, katibh.project.walkersquest.Account.StepCounterService.StepCountUpdaterAlarm.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,    intent, 0);

    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.DAY_OF_YEAR, -1);
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 50);
    calendar.set(Calendar.SECOND, 00);


    SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
    Date date = new Date(System.currentTimeMillis());
    debugInfo.add("Attempted update at:" + formatter.format(date));

    while(calendar.getTimeInMillis() < System.currentTimeMillis())
    {
        calendar.add(Calendar.MINUTE, 1);
    }

    debugInfo.add("Attempting next update at:" + calendar.getTime());

    // CANNOT RUN ALARM EVERY MINUTE IN setAndAllowWhileIdle, ONE MINUTE ALARM IS FOR TESTING PURPOSES
    //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    //            alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
    //        } else {
                   alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
    //        }
}

@Override
public void handleMessage(@NonNull Message msg) {
    super.handleMessage(msg);
}

@Override
public void onSensorChanged(SensorEvent event) {
    int totalSteps = (int) event.values[0];
    if(onSensorChangedFirstCall)
    {
        previousSteps = totalSteps;
        onSensorChangedFirstCall = false;
    }

    cumulativeSteps = totalSteps - previousSteps;
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

public synchronized int getCumulativeSteps()
{
    cumulativeSteps = (int)(5000.0 * new Random().nextDouble());
    return cumulativeSteps;
}

public synchronized void resetStepsCounter() {
    cumulativeSteps = 0;
    previousSteps = 0;
    onSensorChangedFirstCall = true;
}
}

Broadcast Receiver:

public class StepCountUpdaterAlarm extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    //Handler is null here when i the code below is executed.
    StepCounterHandler handler = StepCounterHandler.getInstance();
              
    //Do something...
    sendToServer(handler.getCumultiveSteps)
    handler.setAlarm(context);

    if(isTimeToReset())
       handler.resetStepsCounter();
}

private boolean isTimeToReset()
{
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 50);
    calendar.set(Calendar.SECOND, 00);

    return calendar.getTimeInMillis() < System.currentTimeMillis();
}
}

上面的例子设置并应该每分钟触发一次alert (出于测试目的),所以我使用set方法.我知道setAndAllowWhileIdle每15分钟只能发送一次,但主要问题是我无法在接收器中获取处理程序的实例.它总是返回null,我不知道为什么.

推荐答案

如果零参数getInstance()返回null,则没有单例.

你有两个过程.StepCounterService:stepCounterService过程中.StepCountUpdaterAlarm处于默认过程中.这些进程不共享对象,因此它们将有单独的StepCounterHandler个单实例.如果您之前没有在默认过程中设置StepCounterHandler,那么它将是null.

如果你希望在StepCounterServiceStepCountUpdaterAlarm之间分享单身,他们需要在同一个过程中.要么将StepCountUpdaterAlarm移动到:stepCounterService过程中,要么将StepCounterService移动到默认过程中.

Android相关问答推荐

Android设备.Net Maui上的mp3文件列表

懒惰的垂直网格中盒子的重量-Jetpack组合

合成-删除图像的部分背景

Jetpack编写使用自定义主题覆盖库中主题部分

无法在Android中创建通知频道

在androidStudio中,如何使用带有ResolutionStrategy的ResolutionSelector而不是setTargetResolve()?

使用 List 和 LazyColumn 重新组合所有项目

如何在卡片视图右侧添加箭头

是否可以在 Android 应用程序的 Wifi 设置中为 DNS 服务器设置自定义 IP?

在段的中心绘制饼图(甜甜圈图)的图例

Jetpack Compose UI - 在 AlertDialog 中单击时按钮宽度会发生变化

我应该使用 Bluetooth Classic 还是 Bluetooth LE 与我的移动应用程序通信?

在 android list 中添加 IsMonitoringTool 元数据标志的位置

在 Compose 中使用 DeepLink 会导致无法向后导航

如何删除 Ktor 客户端 2.0.0 的默认标头

如何使伴奏导航 BottomSheet 完全展开?

Android:如何获取具有纬度和经度的位置的图像

Android Wifi-API 在 Android 10+ 上真的那么糟糕吗?

compose UI 测试 - 如何断言文本 colored颜色 ?

当 primaryDark 为白色时更改状态栏文本 colored颜色