如何停止 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()
。
我正在尝试从我的 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()
。