0

我正在构建一个应用程序来控制 LED 灯泡(Mi-Light、limitlessLed 等)。该应用程序的目的是具有用户可以选择并让其无限期运行的效果。例如,“烛光”效果可能会或多或少随机地在黄色和红色之间改变灯泡颜色,直到用户决定停止。

快速背景信息:这些灯泡的控制方式是通过 WiFi 网络发送的 UDP 包。因此,即使设备处于睡眠状态,我也需要该应用程序继续发送此类 UDP 数据包。

经过一番研究,我最终使用了唤醒锁,以便让设备即使在睡眠时也能通过 WiFi 网络广播 UDP 包(请告诉我,以防有更好的方法我没有发现)。

一切正常运行几分钟(也许 10 分钟?),直到设备似乎进入某种深度睡眠模式并停止通过网络发送包。

我怎样才能防止这种情况发生?更一般地说,为了完成上述内容,我应该采取什么好的方法?

仅供参考,这是一个示例代码片段,它只是在 7 种颜色的数组中旋转:

[...]

  private static boolean animationRunning = false;
  private Timer timer = new Timer();
  private PowerManager mgr = (PowerManager)getReactApplicationContext().getSystemService(Context.POWER_SERVICE);
  private PowerManager.WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");

[...]

public void startAnimation(final int step) {

animationRunning = true;
wakeLock.acquire();

final int[] steps = { 0, 66, 99, 122, 166, 199, 255 };

resetTimer();
timer.scheduleAtFixedRate(new TimerTask(){
  int curstep = 0;
  @Override
  public void run(){
    byte[] Bytes = {64, (byte)steps[curstep], 85};
    try {sendUdp(Bytes);} catch(IOException e) {};
    curstep = curstep + 1;

    if(curstep == steps.length) {
      curstep = 1;
    }
  }
},0,1000);
}
4

2 回答 2

2

我最终实现了前台服务(startForeground()),如此处所述

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

        _acquireWakelock();

        _showNotification();

        [do your thing]

        return START_REDELIVER_INTENT;
}

private void _showNotification() {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.setAction("com.lightcontrollerrn2.action.main");
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
            | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);

    Bitmap icon = BitmapFactory.decodeResource(getResources(),
            R.mipmap.ic_launcher);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle("Light Controller")
            .setTicker("Light Controller")
            .setContentText("Light effects are running")
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setContentIntent(pendingIntent)
            .setOngoing(true)
            .build();

    startForeground(1337,
            notification);
}

我在此过程中发现的几件事也可能对其他人有所帮助:

  1. 前台服务仍然需要唤醒锁才能在设备空闲时继续运行;

  2. 您可能会遇到类似问题的另一个原因是 Android 6.0 中引入的新打盹模式 ( https://developer.android.com/training/monitoring-device-state/doze-standby.html )。不过,就我而言,该服务似乎可以持续运行足够长的时间,而无需我处理设备进入打瞌睡模式(我测试了大约一小时,对此我很满意)。编辑:为了完成,我也解决了这个问题。以下是您的操作方式(在服务本身内):

    @Override
    public void onCreate() {
        super.onCreate();
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        String packageName = getPackageName();
        if (Build.VERSION.SDK_INT >= 23 && !pm.isIgnoringBatteryOptimizations(packageName)) {
            Intent intent = new Intent();
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + packageName));
            startActivity(intent);
        }
    }
    
于 2016-06-17T14:47:15.183 回答
0

我可以想到两种方法来满足您的要求。

  1. 如果您可以将应用程序保持在前台,则可以通过添加到您的活动来防止设备进入睡眠状态android:keepScreenOn="true"(有关更多信息,请参阅https://developer.android.com/training/scheduling/wakelock.html)。

  2. 第二种方法是假装您的应用程序正在后台播放音乐,因此不会被操作系统杀死。您可以播放本地存储在应用程序中的无声 mp3,然后无限次重复播放。操作系统永远不会杀死你的应用程序,直到它耗尽电池:)

希望能帮助到你。

于 2016-06-13T16:58:54.240 回答