1

I am trying to read sensor data from my phone. I have started a service, which created a HandlerThread to collect sensor data. The thread registers the sensor for a short while and unregisters it. When I stop the service, however, the thread keeps running, and I see print statements working. How do I stop this? This is my service code.

package com.example.myapplication;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;

@RequiresApi(api = Build.VERSION_CODES.O)
public class SenseService extends Service {

    private Looper serviceLooper;
    private ServiceHandler serviceHandler;
    private Context context;
    private HandlerThread thread;


    private final class ServiceHandler extends Handler implements SensorEventListener {
        private SensorManager sensorManager;
        private Sensor mLight;
        private LocalDateTime currTime;
        private String senseTime;
        private String FILENAME="sensordata";
        private FileOutputStream fos;

        public ServiceHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            try {
                currTime = java.time.LocalDateTime.now();
                String newFileName  = currTime.toString()+FILENAME+".csv";
                fos = openFileOutput(newFileName, Context.MODE_APPEND);
            } catch (FileNotFoundException e) {
                System.out.println("did not open file");
                e.printStackTrace();
            }
            sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
            mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

            try {
                do {
                    sensorManager.registerListener(this, mLight, 10000000);
                    Thread.sleep(2000);
                    System.out.println("thread sleeping");
                    sensorManager.unregisterListener(this);
                    Thread.sleep(5000);
                } while (true);
            }catch (InterruptedException e) {
                e.printStackTrace();
            } {

            }
            stopSelf(msg.arg1);
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            float lux = event.values[0];
            String val = Float.toString(lux);
            senseTime = java.time.LocalDateTime.now().toString();
            System.out.println(Float.toString(lux));
            val = senseTime+","+val+"\n";

            try {
                fos.write(val.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    }

    @Override
    public void onCreate(){
        thread = new HandlerThread("ServiceStartArguments");
        thread.start();

        serviceLooper = thread.getLooper();
        serviceHandler = new ServiceHandler(serviceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
        Message msg = serviceHandler.obtainMessage();
        msg.arg1 = startId;
        serviceHandler.sendMessage(msg);
        return START_STICKY;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
        System.out.println("Stopping service");
        thread.quitSafely();
        stopSelf();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
Brotchu
  • 115
  • 1
  • 8
  • 1
    Does this answer your question? [stop service in android](https://stackoverflow.com/questions/5555765/stop-service-in-android) – BroscR Oct 17 '21 at 11:18
  • The service is stopping when i click button. i see a toast. But the HandlerThread which was started in the service, it keeps going . I added thread.quitSafely() in onDestroy() but that doesn't work – Brotchu Oct 17 '21 at 11:29
  • How are you trying to stop the service? – Ryan M Oct 19 '21 at 02:08
  • I stop the service using stopService(): I have two buttons, start and stop. onClick takes stop and calls stopService() `stopService( serviceIntent);` – Brotchu Oct 19 '21 at 13:06

1 Answers1

1

You use large amount of delays to put the threads into the sleep state. Also you are using an infinite loop without any condition to break the loop here:

do {
    sensorManager.registerListener(this, mLight, 10000000);
    Thread.sleep(2000);
    System.out.println("thread sleeping");
    sensorManager.unregisterListener(this);
    Thread.sleep(5000);
} while (true); // Define a condition or interrupt the thread

In this condition the handlerthread's looper will not quit until the all messages in the queue are handled. But with your implementation it will always be occupied with the first message due to that infinite loop.

You must either somehow interrupt the threads or put a condition to that infinite loop if you want that all messages be handled when you quit safely from handler thread. Or if no further processing needed when the service is stopped, you can try the quit() method instead of quitSafely().

Kozmotronik
  • 2,080
  • 3
  • 10
  • 25
  • thank you. this helped me. I tried to `quit()` instead of `quitSafely()` but that didn't work. However, I put a condition on loop, and set a flag for service running status. That worked and the service stops when I use the button. – Brotchu Nov 03 '21 at 22:59