工作完成后无法停止工作人员(ListenableWorker)任务

Can't stop worker (ListenableWorker) task when work has finished

我似乎找不到停止工作任务的正确方法。我在我的 ResolvableFuture<Result> 上调用 .set(Result.success());,但它永远不会在我的 class 中触发 onStopped(),并且其他订阅的回调似乎在我的工作人员中仍然有效。

在我连接到 BLE 设备后调用 Result.success() 后,它仍然会在 connectGatt() 函数中保持对 onConnectionStateChange 的活动引用。

即使在 OS 强行停止我的工作人员之后,它似乎也没有调用 onStopped(),因为我不记得在日志中看到过它。

即使在创建了一个新的 worker 之后,我仍然可以通过 onConnectionStateChange

在旧的 worker 中获得更新
package test;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.concurrent.futures.ResolvableFuture;
import androidx.work.ListenableWorker;
import androidx.work.WorkerParameters;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;

import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
import static android.os.Build.VERSION_CODES.M;

public class BluetoothScanWorker extends ListenableWorker  {

    private String TAG = "BluetoothScanWorker";
    private BluetoothAdapter bluetoothAdapter;
    private ResolvableFuture<Result> mFuture;


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

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        mFuture = ResolvableFuture.create();

        Log.d(TAG ,"startWork()");

        if (Build.VERSION.SDK_INT >= M) {
            ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build();
            List<ScanFilter> filters_v2 = new ArrayList<>();
            ScanFilter scanFilter = new ScanFilter.Builder()
                    .setDeviceAddress("B8:27:EB:B9:5C:FC")
                    .build();
            filters_v2.add(scanFilter);
            BluetoothManager bluetoothManager =
                    (BluetoothManager) this.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
            bluetoothAdapter = bluetoothManager.getAdapter();
            bluetoothAdapter.getBluetoothLeScanner().startScan(filters_v2, settings, leScanCallback); // Scan for every BLE device matching my filter

            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    endWork();
                }
            }, 3*60*1000); // End worker after 3 minutes
        }
        return mFuture;
    }


    private void endWork(){
        if (Build.VERSION.SDK_INT >= M) {
            Log.d(TAG, "END WORK");
            bluetoothAdapter.getBluetoothLeScanner().stopScan(leScanCallback);
            mFuture.set(Result.success());
        }
    }


    @RequiresApi(M)
    private ScanCallback leScanCallback = new ScanCallback() { // Called when I find my BLE device
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.d(TAG ,"onScanResult: " + result.getDevice().toString());
            bluetoothAdapter.getBluetoothLeScanner().stopScan(this);
            result.getDevice().connectGatt(getApplicationContext(), true, new BluetoothGattCallback() { // Connect to my BLE device
                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            Log.d(TAG ,"GATT connected successfully");
                            endWork();
                        }
                    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                        Log.d(TAG ,"GATT disconnected");
                        endWork();
                    }

                }
            },TRANSPORT_LE);

        }
    };


    @Override
    public void onStopped() {
        Log.d(TAG, "Work service stopped");
    }

}

注意,ListenableWorker.onStopped()方法只有在worker被取消或任务被系统抢占时才会被调用。如果工作人员已成功完成,则不会调用 onStop()onStop() documentation tells:

This method is invoked when this Worker has been told to stop. ... This could happen due to an explicit cancellation signal by the user, or because the system has decided to preempt the task. ...

有时即使worker成功完成也可以调用onStop()回调,但是a bug that will be fixed in the future. Take a look at this post: