重新启动时未启动前台服务

时间:2021-07-12 21:19:02

标签: java android android-studio mobile mobile-development

我正在开发一个需要前台服务来通过蓝牙与计算机同步数据的 Android 应用程序。前台服务在应用程序首次运行的会话期间完美运行。但是,如果我重新启动手机,即使我在 onStartCommand 函数中返回了 START_STICKY,该服务也不会在重新启动时重新启动。我希望它在重新启动后尽快启动,就像我的 VPN 一样。我怎样才能实现这个功能?

这是有问题的代码:

package com.example.app;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.IBinder;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Set;

import static com.example.app.App.CONNECTED_DEVICES_CHANNEL_ID;

public class BluetoothSyncService extends Service {
    private Utils utils;

    private final BluetoothAdapter BLUETOOTH_ADAPTER = BluetoothAdapter.getDefaultAdapter();
    private final String CONNECTED_PC_GROUP = "connectedPCS";
    private final ArrayList<String> NOTIFIED_PC_ADDRESSES = new ArrayList<>();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        utils = Utils.getInstance(this);

        NotificationCompat.Builder summaryNotificationBuilder =
                new NotificationCompat.Builder(this,
                        CONNECTED_DEVICES_CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_placeholder_logo)
                        .setContentTitle("Sync Service Background")
                        .setGroup(CONNECTED_PC_GROUP)
                        .setGroupSummary(true)
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setOngoing(true);

        int SUMMARY_NOTIFICATION_ID = 69;
        startForeground(SUMMARY_NOTIFICATION_ID, summaryNotificationBuilder.build());

        Thread serviceThread = new Thread(() -> {
            while (true) {
                handleConnectedDevices();
                handleNotifications();
            }
        });
        serviceThread.start();

        return START_STICKY;
    }

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

    private void handleConnectedDevices() {
        Set<BluetoothDevice> pairedDevices = BLUETOOTH_ADAPTER.getBondedDevices();

        // Handle connected PCS
        for (BluetoothDevice device : pairedDevices) {
            if (isConnected(device.getAddress())) {
                int deviceClass = device.getBluetoothClass().getDeviceClass();

                if (deviceClass == BluetoothClass.Device.COMPUTER_LAPTOP |
                        deviceClass == BluetoothClass.Device.COMPUTER_DESKTOP) {
                    if (!utils.inPairedPCS(device.getAddress())) {
                        utils.addToPairedPCS(new PairedPC(device.getName(),
                                device.getAddress(), true));
                    } else {
                        if (utils.getPairedPCByAddress(device.getAddress()) != null) {
                            utils.getPairedPCByAddress(device.getAddress()).setConnected(true);
                            utils.savePairedPCSToDevice();
                        }
                    }
                }
            } else {
                if (utils.inPairedPCS(device.getAddress())) {
                    if (utils.getPairedPCByAddress(device.getAddress()) != null) {
                        utils.getPairedPCByAddress(device.getAddress()).setConnected(false);
                        utils.savePairedPCSToDevice();
                    }
                }
            }
        }
    }

    private void handleNotifications() {
        NotificationManagerCompat notificationManager = NotificationManagerCompat
                .from(this);

        for (PairedPC pairedPC : utils.getPairedPCS()) {
            int CONNECTION_NOTIFICATION_ID = 420;
            if (pairedPC.isConnected()) {
                if (pairedPC.isActive() && !NOTIFIED_PC_ADDRESSES.contains(pairedPC.getAddress())) {
                    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
                            this, CONNECTED_DEVICES_CHANNEL_ID)
                            .setSmallIcon(R.drawable.ic_pc)
                            .setContentTitle("Syncing PC")
                            .setContentText(pairedPC.getName())
                            .setGroup(CONNECTED_PC_GROUP)
                            .setPriority(NotificationCompat.PRIORITY_MIN)
                            .setOngoing(true);

                    notificationManager.notify(pairedPC.getAddress(),
                            CONNECTION_NOTIFICATION_ID, notificationBuilder.build());
                    NOTIFIED_PC_ADDRESSES.add(pairedPC.getAddress());
                } else if (!pairedPC.isActive()) {
                    notificationManager.cancel(pairedPC.getAddress(), CONNECTION_NOTIFICATION_ID);
                    NOTIFIED_PC_ADDRESSES.remove(pairedPC.getAddress());
                }
            } else {
                if (NOTIFIED_PC_ADDRESSES.contains(pairedPC.getAddress())) {
                    notificationManager.cancel(pairedPC.getAddress(), CONNECTION_NOTIFICATION_ID);
                    NOTIFIED_PC_ADDRESSES.remove(pairedPC.getAddress());
                }
            }
        }
    }

    private boolean isConnected(String address) {
        Set<BluetoothDevice> pairedDevices = BLUETOOTH_ADAPTER.getBondedDevices();
        for (BluetoothDevice device : pairedDevices) {
            if (device.getAddress().equals(address)) {
                Method method = null;
                try {
                    method = device.getClass().getMethod("isConnected", (Class[]) null);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }

                boolean connected = false;
                try {
                    assert method != null;
                    Object methodInvocation = method.invoke(device, (Object[]) null);
                    if (methodInvocation != null) {
                        connected = (boolean) methodInvocation;
                    } else {
                        connected = false;
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }

                return connected;
            }
        }
        return false;
    }
}

编辑:

所以我尝试按照建议使用广播接收器。然而它仍然无法正常工作。这是接收器的代码:

package com.example.app;

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

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            Intent syncServiceIntent = new Intent(context, BluetoothSyncService.class);
            context.startService(syncServiceIntent);
        }
    }
}

这是我的清单:

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

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>


    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:name=".App"
        android:theme="@style/Theme.App">

        <receiver android:name=".BootReceiver" android:enabled="true" android:exported="true">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            </intent-filter>
        </receiver>

        <activity android:name=".PermissionsActivity" />
        <activity android:name=".MainActivity" />
        <activity android:name=".StartupActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".BluetoothSyncService"/>
    </application>

</manifest>

编辑 2:

解决了!不得不改变 context.startService(syncServiceIntent);到 context.startForegroundService(syncServiceIntent);

0 个答案:

没有答案