当应用程序关闭时,使用广播接收器的工作管理器无法正常工作

6
我只想让蓝牙保持开启状态,为此我监听蓝牙的状态,如果关闭了,则广播接收器可将其启用。并且我希望即使应用程序关闭后也能运行。因此,我尝试在应用程序关闭后仍运行蓝牙广播接收器(在不工作时)。为此,我了解到需要使用 Work Manager 来支持所有设备。我尝试将 广播接收器和 Work Manager 结合 使用。但无法在应用程序关闭时运行它。
这是我的 MainActivity.java,我在其中排队工作请求。
package com.example.workmanagersample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).build();
        WorkManager.getInstance().enqueue(workRequest);

    }
}

以下类是我的 MyWorker.java。在这里,我注册了接收器。
package com.example.workmanagersample;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import androidx.work.Worker;
import androidx.work.WorkerParameters;


public class MyWorker extends Worker {
    private BlueToothBroadcastReceiver myReceiver;

    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    /*
     * This method is responsible for doing the work
     * so whatever work that is needed to be performed
     * we will put it here
     *
     * For example, here I am calling the method displayNotification()
     * It will display a notification
     * So that we will understand the work is executed
     * */

    @NonNull
    @Override
    public Result doWork() {
        displayNotification("My Worker", "Hey I finished my work");


        setReceiver();

        return Worker.Result.success();
    }

    /*
     * The method is doing nothing but only generating
     * a simple notification
     * If you are confused about it
     * you should check the Android Notification Tutorial
     * */
    private void displayNotification(String title, String task) {
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("simplifiedcoding", "simplifiedcoding", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "simplifiedcoding")
                .setContentTitle(title)
                .setContentText(task)
                .setSmallIcon(R.mipmap.ic_launcher);

        notificationManager.notify(1, notification.build());
    }


    private void setReceiver() {
        myReceiver = new BlueToothBroadcastReceiver();
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        getApplicationContext().registerReceiver(myReceiver, filter);

    }
}

以下是我的 BlueToothBroadcastReceiver.java 类,我在这里监听蓝牙状态的变化,并尝试在它关闭时打开它。当应用程序正在运行时,它能够正常工作。但是我希望它也可以在应用程序关闭时工作,但我无法实现它。
package com.example.workmanagersample;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BlueToothBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();

        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                    BluetoothAdapter.ERROR);
            switch (state) {
                case BluetoothAdapter.STATE_OFF:
                    setBluetooth(true);
                    // Bluetooth has been turned off;
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    setBluetooth(true);
                    // Bluetooth is turning off;
                    break;
                case BluetoothAdapter.STATE_ON:
                    // Bluetooth has been on
                    break;
                case BluetoothAdapter.STATE_DISCONNECTING:
                    setBluetooth(true);
                    // Bluetooth is turning on
                    break;

                case BluetoothAdapter.STATE_DISCONNECTED:
                    setBluetooth(true);
                    // Bluetooth is turning on
                    break;
            }
        }
    }

    public static boolean setBluetooth(boolean enable) {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        boolean isEnabled = bluetoothAdapter.isEnabled();
        if (enable && !isEnabled) {
            return bluetoothAdapter.enable();
        }
        else if(!enable && isEnabled) {
            return bluetoothAdapter.disable();
        }
        // No need to change bluetooth state
        return true;
    }
}

最后是我的清单文件;

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.workmanagersample">

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver
            android:name=".BlueToothBroadcastReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
                <action android:name="android.bluetooth.adapter.action.STATE_OFF"/>
                <action android:name="android.bluetooth.adapter.action.STATE_TURNING_OFF"/>
                <action android:name="android.bluetooth.adapter.action.STATE_ON"/>
                <action android:name="android.bluetooth.adapter.action.STATE_DISCONNECTING"/>
                <action android:name="android.bluetooth.adapter.action.STATE_DISCONNECTED"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

在周末进行了研究后,我选择使用Work Manager,但是当我关闭应用程序时它并没有起作用。是否有什么我错过的内容或者有任何限制?如果有,我该如何解决?非常感谢您的帮助!谢谢!

3个回答

2
WorkManager旨在即使在应用程序处于后台时也能执行任务。您可以为Worker类分配一些约束条件,以便仅在满足这些约束条件时执行它们(例如,如果您需要将某些数据上传到服务器,则具有WiFi连接可用的约束条件)。
这就是为什么WorkManager使用广播接收器(在API级别22及以下)或JobScheduler的原因:以了解这些约束条件何时发生变化。
正如其他人所回复的那样,您需要使用Service(如果需要长时间运行,则可能使用前台Service是一个好主意)。 您应该评估的几个要点:
  1. 首先检查前台服务的情况。请考虑此博客文章
  2. 然后查看前台服务文档
  3. 最后查看蓝牙概述

0

背景

现在来看你的实现,似乎你有一些提示,因为我看到你有未决的通知。因为这部分非常接近解决方案。所以实际上你必须使用前台服务(而不仅仅是这里提到的服务,因为它可能会被系统终止)。

最后,我相信你有运行这个应用程序的用例。因为它可能会对用户造成很大的功耗,而你知道自己在做什么。

解决方案

实现前台服务并从应用程序启动它。确保您内部有通知。和您的接收器订阅的实现。

class LiveBroadcast : Service() {

    private var myReceiver: BlueToothBroadcastReceiver? = null

    override fun onCreate() {

        // Init Forgeround Notification
        val pendingIntent: PendingIntent =
            Intent(this, ExampleActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 0, notificationIntent, 0)
            }

        val notification: Notification = Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
                .setContentTitle(getText(R.string.notification_title))
                .setContentText(getText(R.string.notification_message))
                .setSmallIcon(R.drawable.icon)
                .setContentIntent(pendingIntent)
                .setTicker(getText(R.string.ticker_text))
                .build()

        // Notification ID cannot be 0.
        startForeground(ONGOING_NOTIFICATION_ID, notification)

        // Start your BluetoothReceiver
        myReceiver = new BlueToothBroadcastReceiver()
        getApplicationContext().registerReceiver(
            myReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        // Pass
    }

    override fun onDestroy() {
        // Pass
    }
}

你的答案是错误的,请看这里:https://dev59.com/81UL5IYBdhLWcg3wb3pz 我们可以在 doWork() 中启动蓝牙接收器。 - user14016240
@SychiSingh 我确实从答案中删除了“Worker”的提及。但是使用Service进行后台工作有不同的目的,在您的情况下,我认为应该使用前台服务。无论如何,在测试期间我的更改都完美地运行。 - GensaGames
@AnirudhGanesh 你没有恰当地回答。用户可能会杀掉应用程序,那么呢? - user14016240
如果他们杀死了它,而且如果它碰巧是中国制造商,那么无论是否关闭电池优化,您的应用程序的后台都将停止。当我联系谷歌时,他们建议我使用最新的API进行测试,因为他们已经在后来的版本中解决了这个问题(在一加北极星上运行)。对于旧版本,您可以检查它们的API级别并教育他们关闭后台优化。有关如何关闭各种制造商的优化的更多信息,请访问https://bitbucket.org/copluk/acr/issues/607。即使应用程序没有被滑动掉,这也是必需的! - Anirudh Ganesh
显示剩余2条评论

0

你需要在应用关闭后保持广播接收器运行,并使用 Service 类来实现,你可能想查看 this 的回答。


据我所了解,这在 Android 6 及以上版本中不起作用。首先,我使用 IntentService 实现了相同的项目,然后是 Service。但它们也没有起作用,当我搜索时,我了解到如果我需要在更高的设备上运行它,我需要使用 Work Manager。所以最终我选择了 Work Manager。然而,它仍然不起作用。 - Hilal
我应该把它放在这一行下面 WorkManager.getInstance().enqueue(workRequest); 吗? - Hilal
3
请查看此链接:https://medium.com/androiddevelopers/workmanager-basics-beba51e94048 - Mohammad Sommakia
哦,它说广播接收器在API 23及更高版本中被禁用了。https://developer.android.com/reference/androidx/work/package-summary 我还应该做什么?当应用程序关闭时,应该有一种方法来监听蓝牙状态的变化。 - Hilal
使用JobScheduler来替代WorkManager,适用于API 23以上的版本。 - Prajwal Waingankar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接