6

我创建了一个应用程序,它需要在后台不断扫描我们自己的蓝牙设备。当其中一台蓝牙设备在附近时,应用程序需要执行某些操作。

我使用绑定的前台服务来扫描蓝牙设备,当设备在附近时,应用程序开始侦听位置更新。当设备不在附近时,应用程序会停止位置更新并重新开始扫描。在奥利奥之前,这一直很好用。

在 Android Oreo 上,服务通常在运行 2-3 天后停止。我不知道为什么会这样。

这就是我在主要活动中创建服务的方式:

private void initServiceConnection() {
    mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service)
        {
            mService = ((MyService.LocalBinder) service).getService();
            mService.startBLEScan();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName)
        {
            // When the service is killed we restart the app in onDestroy by calling finish() here
            mService = null;
            finish();
        }
    };

    Intent serviceIntent = new Intent(this, MyService.class);
    bindService(serviceIntent, mServiceConnection, BIND_AUTO_CREATE | BIND_IMPORTANT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(serviceIntent);
    }
}

这是该服务的简化版本:

public class MyService extends Service
{    
    private static final long SCAN_TIMEOUT  = 8000;
    private static final long PAUSE_TIMEOUT = 15000;

    private Handler mHandler;
    private BluetoothAdapter mBluetoothAdapter;
    private final IBinder mBinder = new LocalBinder();

    public MyService()
    {
        mHandler = new Handler();
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return mBinder;
    }

    public void initialize()
    {
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

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

        startInForeground();
        initialize();
    }

    @Override
    public void onDestroy()
    {
        mHandler.removeCallbacks(timeoutScan);
        mHandler.removeCallbacks(timeoutPause);

        stopForeground(true);

        stopScan();

        super.onDestroy();
    }

    public class LocalBinder extends Binder
    {
        public MyService getService()
        {
            return MyService.this;
        }
    }

    private void startInForeground()
    {
        NotificationCompat.Builder mNotifyBuilder;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            MyNotificationManager notificationManager = new MyNotificationManager(getApplicationContext());
            notificationManager.createServiceNotificationChannel();

            mNotifyBuilder = new NotificationCompat.Builder(this, notificationManager.getChannelId());
        } else {
            mNotifyBuilder = new NotificationCompat.Builder(this);
        }

        mNotifyBuilder
                .setSmallIcon(R.drawable.ic_logo_notify)
                .setPriority(NotificationCompat.PRIORITY_MAX);

        startForeground(hashCode(), mNotifyBuilder.build());
    }

    private void startScan()
    {
        if (mBluetoothAdapter == null) {
            return;
        }

        mHandler.removeCallbacks(timeoutScan);
        mHandler.removeCallbacks(timeoutPause);

        if (mBluetoothAdapter.isEnabled())
        {
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        }

        mHandler.postDelayed(timeoutScan, SCAN_TIMEOUT);
    }

    private void stopScan()
    {
        mHandler.removeCallbacks(timeoutScan);

        if (mBluetoothAdapter != null)
        {
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }

    private Runnable timeoutScan = new Runnable ()
    {
        @Override
        public void run()
        {
            stopScan();

            mHandler.postDelayed(timeoutPause, PAUSE_TIMEOUT);
        }
    };

    private Runnable timeoutPause = new Runnable ()
    {
        @Override
        public void run()
        {
            startScan();
        }
    };

    private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
    {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, byte[] scanRecord)
        {
            // DO STUFF
        }
    };
} 

我的问题是我做错了什么?我可以在服务被杀死后以某种方式重新启动服务吗?

4

0 回答 0