【问题标题】:Service running in Android 6.0.1 and not in Android 10在 Android 6.0.1 而非 Android 10 中运行的服务
【发布时间】:2020-04-30 13:49:56
【问题描述】:

我在清单中声明了以下服务:


    <application
        ...

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.example.android.test.TestService"
            android:process=":Remote"
            android:permission="android.permission.WAKE_LOCK"/>
        <receiver android:name="com.example.android.test.TestService">
            <intent-filter>
                <action android:name="android.intent.action.BATTERY_CHANGED"/>
            </intent-filter>
        </receiver>
    </application>

这是服务类


public class TestService extends Service implements SensorEventListener {


    public class BatteryReceiver_andFileChecker extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //TODO
        }
        // constructor
        public BatteryReceiver_andFileChecker(){
        }
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        //TODO
        return START_STICKY;
    }

    @SuppressLint("WakelockTimeout")
    @Override
    public void onCreate() {
        super.onCreate();

        Toast.makeText(this, "Logging service started new", Toast.LENGTH_SHORT).show();

        //Acquire wake lock
        PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
        this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WLTAG:MyWakelockTag");
        wakeLock.acquire();

        //Display notification
        this.notIntent = new Intent(this, MainActivity.class);
        this.pendingIntent = PendingIntent.getActivity(this, 0, this.notIntent, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, this.channelID).setSmallIcon(R.drawable.ic_launcher_background).setContentTitle("Test").setContentText("Sensor is recording").setPriority(NotificationCompat.PRIORITY_DEFAULT).setContentIntent(this.pendingIntent);
        startForeground(this.NOTIFICATION, builder.build());


        //BatteryCheck
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        mReceiver = new BatteryReceiver_andFileChecker();
        registerReceiver(mReceiver, filter);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();


        //cancel notification
        stopForeground(true);

        //Unregister battery receiver
        unregisterReceiver(mReceiver);

        //release wakeLock
        wakeLock.release();

        //Stop Service
        stopSelf();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
//        super.onBind(intent);
        return null;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {        
        //TODO
    }

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

    }


}

这个服务是在 MainActivity 的两个不同的“onclick”函数上创建和终止的

public class MainActivity extends AppCompatActivity {
     ...

public void onClickStart(View v) {

        // Start Service
        this.intent = new Intent(getApplicationContext(), TestService.class);
        this.intent.putExtra("foo",foo);
        startService(this.intent);
    }

    public void onClickStopAcquisition(View v) {

        // Stop Service
        stopService(this.intent);
    }
}

此代码在 Android 6.0.1 中按预期运行,但不适用于 Android 10... 当我调试调试应用程序时,在两个操作系统中按下“开始”和“停止”按钮时都不会触发任何错误,但是,android 6.0.1 会触发该服务,而 android 10 不会...

有什么原因吗?

在理解我的实现时要记住,我的目的是创建一个服务,即使用户在应用程序中不活跃,它也能继续运行和做一些事情。由于我实现了 SensorEventListener 来记录来自传感器的数据,因此我的目的是在用户可能正在与手机交互甚至什么都不做时记录数据(在他按下手机的电源按钮后,服务会继续运行以获取数据并执行操作)

然后,服务应该在用户单击停止按钮或 MainActivity 终止时终止。

谢谢!

【问题讨论】:

    标签: android service android-service android-sensors android-version


    【解决方案1】:

    我想你应该阅读更多关于后台服务和 Android API 26 或更高版本的广播

    来自官方文档here

    如果应用注册接收广播,则应用的接收器在每次发送广播时都会消耗资源。如果太多的应用程序注册以接收基于系统事件的广播,这可能会导致问题;触发广播的系统事件会导致所有这些应用程序快速连续消耗资源,从而影响用户体验。为了缓解这个问题,Android 7.0 (API level 24) 对广播设置了限制,如背景优化中所述。 Android 8.0 (API level 26) 使这些限制更加严格。

    Android 8.0更高为目标的应用无法再注册 清单中隐式广播的广播接收器。一个 隐式广播是不针对该应用程序的广播 具体来说。例如,ACTION_PACKAGE_REPLACED 是一个隐式 广播,因为它被发送给所有注册的听众,让他们 知道设备上的某些包已被替换。然而, ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为它是 只发送到包被替换的应用,不管有多少 其他应用程序已为该广播注册了侦听器。应用程序可以 继续在其清单中注册显式广播。应用 可以在运行时使用Context.registerReceiver()来注册一个接收器 对于任何广播,无论是隐式的还是显式的。

    需要签名权限的广播不受此限制,因为这些广播仅发送到使用相同证书签名的应用,而不是设备上的所有应用

    您应该使用 JobScheduler

    重要更新

    在评论中回答您的问题:使用WorkManager 处理可延期的后台任务。

    这个库是向后兼容的

    它使用JobScheduler,FirebaseJobDispatcherAlarmManager

    无需依赖播放服务库。

    Google 推荐用于延迟后台工作。

    可以使用链接、约束等功能。

    【讨论】:

    • 感谢您的评论,我将查看 JobScheduler 类以更好地了解如何进行。只是几件事:你知道任何可靠的带有 SensorEventListener 的作业调度程序示例吗? JobScheduler 是否与 API19 兼容?
    • 感谢您在回答中的更新!确实,你帮了大忙!最后一个问题,您认为 WorkManager 可以与 SensorEventListener 结合以在较长的获取周期内持续获取 Acc 吗?可以说:单击按钮,Acc 开始获取。连续获取 Acc 10 小时,直到再次单击按钮并停止获取 Acc。这可以通过 WorkManager 实现吗?
    • 对于我一直在阅读的内容,可能是我需要实现 ForegroundService,并且没有执行的原因是因为我缺乏“ForeGroundService”权限吗? (developer.android.com/guide/components/services#Foreground)
    猜你喜欢
    • 2017-10-01
    • 1970-01-01
    • 2017-07-01
    • 2013-05-02
    • 2016-10-19
    • 1970-01-01
    • 2014-04-11
    • 2017-08-04
    • 1970-01-01
    相关资源
    最近更新 更多