如何停止 Android 中使用 HandlerThread 的 ServiceHandler?

How to stop a ServiceHandler in Android, which uses HandlerThread?

我正在尝试从我的 phone 读取传感器数据。我已经启动了一项服务,它创建了一个 HandlerThread 来收集传感器数据。线程会暂时注册传感器并注销它。但是,当我停止服务时,线程保持 运行,并且我看到打印语句在工作。我该如何阻止呢?这是我的服务代码。

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;
    }
}

您使用大量延迟使线程进入睡眠状态。此外,您正在使用无限循环,没有任何条件来打破循环:

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

在这种情况下,处理线程的循环程序将不会退出,直到处理完队列中的所有消息。但是在你的实现中,由于无限循环,它总是会被第一条消息占用。

如果您希望在从处理程序线程安全退出时处理所有消息,则必须以某种方式中断线程或为该无限循环设置条件。 或者如果服务停止时不需要进一步处理,您可以尝试 quit() 方法而不是 quitSafely()