android:无法停止前台服务通知

o4tp2gmn  于 2021-07-12  发布在  Java
关注(0)|答案(0)|浏览(365)

我试图用一个开关按钮启动和停止服务,但一旦服务启动,它就会执行任务,当开关按钮关闭时,它不会执行stopservice();

从mainactivity内的共享首选项(sharedpref.getisautochange())检索开关按钮的状态

if (sharedPref.getIsAutoChange()) {
        startService();
        Log.d(TAG, "Service Started");
    } else {
        stopService();
        Log.d(TAG, "Service Stopped");
  }

mainactivity中的方法

public void startService() {
    Log.d(TAG, "startService called");
    if (!MyService.isServiceRunning) {
        Intent serviceIntent = new Intent(this, MyService.class);
        ContextCompat.startForegroundService(this, serviceIntent);
        //startService(serviceIntent);
    }
}

public void stopService() {
    Log.d(TAG, "stopService called");
    if (MyService.isServiceRunning) {
        Intent serviceIntent = new Intent(this, MyService.class);
        stopService(serviceIntent);
    }
}

public void startServiceViaWorker() {
    Log.d(TAG, "startServiceViaWorker called");
    String UNIQUE_WORK_NAME = "StartMyServiceViaWorker";
    //String WORKER_TAG = "MyServiceWorkerTag";
    WorkManager workManager = WorkManager.getInstance(this);

    // As per Documentation: The minimum repeat interval that can be defined is 15 minutes (
    // same as the JobScheduler API), but in practice 15 doesn't work. Using 16 here
    PeriodicWorkRequest request =
            new PeriodicWorkRequest.Builder(
                    MyWorker.class,
                    16,
                    TimeUnit.MINUTES)
                    //.addTag(WORKER_TAG)
                    .build();
    workManager.enqueueUniquePeriodicWork(UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, request);

我的接收器

public class MyReceiver extends BroadcastReceiver {
    private String TAG = "MyReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive called");

        //ContextCompat.startForegroundService(context, new Intent(context, MyService.class));

        // We are starting MyService via a worker and not directly because since Android 7
        // (but officially since Lollipop!), any process called by a BroadcastReceiver
        // (only manifest-declared receiver) is run at low priority and hence eventually
        // killed by Android.

        WorkManager workManager = WorkManager.getInstance(context);
        OneTimeWorkRequest startServiceRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
                .build();
        workManager.enqueue(startServiceRequest);
    }
}

我的服务

public class MyService extends Service {
    private String TAG = "MyService";
    public static boolean isServiceRunning;
    private String CHANNEL_ID = "NOTIFICATION_CHANNEL";
    private ScreenLockReceiver screenLockReceiver;
    private Timer timer;

    public MyService() {
        Log.d(TAG, "constructor called");
        isServiceRunning = false;
        screenLockReceiver = new ScreenLockReceiver();
        timer = new Timer();
    }

    public void terminateService(){
        this.stopSelf();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate called");
        createNotificationChannel();
        isServiceRunning = true;

        // register receiver to listen for screen on events
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(screenLockReceiver, filter);

        // a dummy timer task - can be ignored
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                Log.d(TAG, "run called inside scheduleAtFixedRate");
            }
        }, 0, PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS);
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d(TAG, "onStartCommand called");
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Service is Running")
                .setContentText("Listening for Screen Off/On events")
                .setSmallIcon(R.drawable.ic_stat_onesignal_default)
                .setContentIntent(pendingIntent)
                .setColor(getResources().getColor(R.color.colorPrimary))
                .build();
        /*
         * A started service can use the startForeground API to put the service in a foreground state,
         * where the system considers it to be something the user is actively aware of and thus not
         * a candidate for killing when low on memory.
         */
        startForeground(1, notification);
        // does not work as expected though, even START_NOT_STICKY gives same result
        // device specific issue?
        return START_STICKY;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String appName = getString(R.string.app_name);
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    appName,
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy called");
        isServiceRunning = false;
        stopForeground(true);

        // unregister receiver
        unregisterReceiver(screenLockReceiver);

        // cancel the timer
        if (timer != null) {
            timer.cancel();
        }

        // call MyReceiver which will restart this service via a worker
        Intent broadcastIntent = new Intent(this, MyReceiver.class);
        sendBroadcast(broadcastIntent);

        super.onDestroy();
    }

    // Not getting called on Xiaomi Redmi Note 7S even when autostart permission is granted
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.d(TAG, "onTaskRemoved called");
        super.onTaskRemoved(rootIntent);
    }

    @Override
    public boolean stopService(Intent name) {
        // TODO Auto-generated method stub
        timer.cancel();
        return super.stopService(name);
    }

}

我的工人

public class MyWorker extends Worker {
    private final Context context;
    private String TAG = "MyWorker";

    public MyWorker(
            @NonNull Context context,
            @NonNull WorkerParameters params) {
        super(context, params);
        this.context = context;
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.d(TAG, "doWork called for: " + this.getId());
        Log.d(TAG, "Service Running: " + MyService.isServiceRunning);
        if (!MyService.isServiceRunning) {
            Log.d(TAG, "starting service from doWork");
            Intent intent = new Intent(this.context, MyService.class);

            /*
             * startForegroundService is similar to startService but with an implicit promise
             * that the service will call startForeground once it begins running.
             * The service is given an amount of time comparable to the ANR interval to do this,
             * otherwise the system will automatically stop the service and declare the app ANR.
             */
            ContextCompat.startForegroundService(context, intent);
            //this.context.startService(intent);
        }
        return Result.success();
    }

    @Override
    public void onStopped() {
        Log.d(TAG, "onStopped called for: " + this.getId());
        super.onStopped();
    }

屏幕锁接收器:监测检查解锁状态(每当屏幕解锁时,我都会使用该服务更改壁纸)

public class ScreenLockReceiver extends BroadcastReceiver {

    private String TAG = "ScreenLockReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        // This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.

        String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_ON)) {
            Log.d(TAG, "onReceive called: screen on");
        } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            Log.d(TAG, "onReceive called: screen off");
        } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
            Log.d(TAG, "onReceive called: screen unlocked");
            new Utils().setRandomWallpaper(context);
        }
    }
}

在舱单里面

<receiver
        android:name=".services.MyReceiver"
        android:enabled="true"
        android:exported="false" />

    <service
        android:name=".services.MyService"
        android:process=":MyService"
        android:enabled="true"
        android:exported="false" />

请帮我解决这个问题。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题