Addendum:Android 框架为一次性工作、后台工作等提供了许多帮助程序,这可能比在许多情况下尝试滚动自己的线程更好。正如下面的文章中提到的,AsyncTask 是一个很好的研究起点。我鼓励读者在开始考虑自己的线程之前先研究一下框架规定。
您发布的代码示例中有几个问题,我将按顺序解决:
1) Thread.stop() 已经被弃用相当长一段时间了,因为在某些情况下它可能会使因变量处于不一致的状态。看本周日答案页面有关更多详细信息(编辑:该链接现已失效,请参阅此页面了解为什么不使用 Thread.stop())。停止和启动线程的首选方法如下(假设您的线程将无限期地运行):
private volatile Thread runner;
public synchronized void startThread(){
if(runner == null){
runner = new Thread(this);
runner.start();
}
}
public synchronized void stopThread(){
if(runner != null){
Thread moribund = runner;
runner = null;
moribund.interrupt();
}
}
public void run(){
while(Thread.currentThread() == runner){
//do stuff which can be interrupted if necessary
}
}
这只是如何停止线程的一个示例,但要点是您有责任退出线程,就像退出任何其他方法一样。维护一种跨线程通信的方法(在本例中是一个易失性变量,也可以通过互斥锁等),并在线程逻辑中使用该通信方法来检查是否应该提前退出、清理等。
2) 您的测量列表由多个线程(事件线程和您的用户线程)同时访问,无需任何同步。看起来您不必自己进行同步,您可以使用阻塞队列.
3)您在发送线程的每次迭代中都会创建一个新的套接字。这是一项相当重量级的操作,只有当您预计测量频率极低(例如每小时一次或更少)时才真正有意义。要么您想要一个不会在线程的每个循环中重新创建的持久套接字,要么您想要一个可以“即发即忘”的一次性运行,它创建一个套接字,发送所有相关数据,然后完成。 (关于使用持久套接字的快速说明,阻塞的套接字方法(例如读取)不能被 Thread.interrupt() 中断,因此当您想要停止线程时,必须关闭套接字并调用中断)
4) 除非您希望在其他地方捕获它,否则从线程中抛出您自己的异常没有什么意义。更好的解决方案是记录错误,如果无法恢复,则停止线程。线程可以使用如下代码停止自身(在与上面相同的上下文中):
public void run(){
while(Thread.currentThread() == runner){
//do stuff which can be interrupted if necessary
if(/*fatal error*/){
stopThread();
return; //optional in this case since the loop will exit anyways
}
}
}
最后,如果您想确保线程与应用程序的其余部分一起退出,无论如何,一个好的技术是在创建线程之后和启动线程之前调用 Thread.setDaemon(true)。这会将线程标记为守护线程,这意味着如果没有非守护线程运行(例如您的应用程序退出),VM 将确保它自动销毁。
遵守有关线程的最佳实践应该确保您的应用程序不会挂起或减慢手机速度,尽管它们可能非常复杂:)