在 Android Service 类中哪里停止/销毁线程?

2023-11-25

我通过以下方式创建了线程服务:

public class TCPClientService extends Service{  
...

@Override
public void onCreate() {
    ...
    Measurements = new LinkedList<String>();
    enableDataSending();    
}

@Override
public IBinder onBind(Intent intent) {
    //TODO: Replace with service binding implementation
    return null;
}

@Override
public void onLowMemory() {
    Measurements.clear();
    super.onLowMemory();
}

@Override
public void onDestroy() {
    Measurements.clear();
    super.onDestroy();
    try {
        SendDataThread.stop();
    } catch(Exception e){
        ...     
    }

}

private Runnable backgrounSendData = new Runnable() {

    public void run() {
        doSendData();
    }
};

private void enableDataSending() {
    SendDataThread = new Thread(null, backgrounSendData, "send_data");
    SendDataThread.start();
}

 private void addMeasurementToQueue() {
     if(Measurements.size() <= 100) {
         String measurement = packData();
         Measurements.add(measurement);
     }
 }

 private void doSendData() {
     while(true) {
         try {      
             if(Measurements.isEmpty()) {
                 Thread.sleep(1000);
                 continue;
             }
             //Log.d("TCP", "C: Connecting...");
             Socket socket = new Socket();
             socket.setTcpNoDelay(true);
             socket.connect(new InetSocketAddress(serverAddress, portNumber), 3000);
             //socket.connect(new InetSocketAddress(serverAddress, portNumber));
             if(!socket.isConnected()) {
                 throw new Exception("Server Unavailable!");
             }
             try {
                 //Log.d("TCP", "C: Sending: '" + message + "'");
                 PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                 String message = Measurements.remove();
                 out.println(message);
                 Thread.sleep(200);
                 Log.d("TCP", "C: Sent.");
                 Log.d("TCP", "C: Done.");
                 connectionAvailable = true;              
             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;
             } finally {
                 socket.close();
                 announceNetworkAvailability(connectionAvailable);
             }
         } catch (Exception e) {
             Log.e("TCP", "C: Error", e);
             connectionAvailable = false;
             announceNetworkAvailability(connectionAvailable);
         }
    }
}

...
}

关闭应用程序后,手机运行速度非常慢,我猜这是由于线程终止失败。

有谁知道在终止应用程序之前终止所有线程的最佳方法是什么?


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 将确保它自动销毁。

遵守有关线程的最佳实践应该确保您的应用程序不会挂起或减慢手机速度,尽管它们可能非常复杂:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Android Service 类中哪里停止/销毁线程? 的相关文章

随机推荐

  • 为什么Java中的private static field = new Singleton不懒呢?

    我读了很多关于 Singleton 的文章 其中大多数作者都说 Java 中 Singleton 的这种变体 public class Singleton private static Singleton instance new Sing
  • 在某个元素之前添加元素

    我有这个代码 td div class imagebutton abc div td 我想在这段代码中添加另一个元素 如下所示 p blablablalblablab p td div class imagebutton abc div t
  • 如何判断 Perl 脚本是否在 CGI 上下文中执行?

    我有一个 Perl 脚本 它将从命令行作为 CGI 运行 从 Perl 脚本中 我如何知道它是如何运行的 最好的选择是检查GATEWAY INTERFACE环境变量 它将包含服务器正在使用的 CGI 协议的版本 这几乎总是CGI 1 1 T
  • 使用 VB 6 代码从任务管理器结束进程

    我需要粗略地终止一个应用程序 以便我可以在我的数据库中获得该应用程序的幻像订阅者 这不能通过关闭应用程序来产生 手动地 如果我们从任务管理器终止应用程序 幻影订阅者将存在 现在我需要在 VB 6 代码中自动完成它 帮助 谢谢 有两种方法 S
  • 使用 download.file() 从 HTTPS 下载文件

    我想使用 R 读取在线数据download file 如下所示 URL lt https d396qusza40orc cloudfront net getdata 2Fdata 2Fss06hid csv download file UR
  • C(非 C++)有限域(伽罗瓦域)线性代数库

    我正在寻找一个有限域 伽罗瓦域C 的精确线性代数库 C 是不可接受的 因为我需要能够编写一个 Haskell 绑定到它 这显然是C 很难 我找到了类似的图书馆FFLAS FFPACK and Givaro但这些是 C 模板库 In part
  • 地址清理程序不适用于 Windows 上的 bash

    目前在 Windows 上的 Ubuntu Bash 上运行 llvm clang clang format 和 clang modernize 我想使用谷歌发布的一套清理工具 包括地址 内存和线程清理 fsanitize 选项似乎都不起作
  • 将字符串转换为 long long

    我正在使用 VS 2008 创建一个 C DLL 非托管 项目 我需要将 char 转换为 long long 类型 有简单的方法吗 提前致谢 最简单的方法是使用 std stringstream 它也是最类型安全的 std strings
  • 兼容类型和参数类型限定符

    这两个声明的类型是否兼容 void f char char void f char restrict char restrict 或类似 void g char void g char const 我很难在标准中找到涵盖该问题的任何内容 我
  • Dropwizard HK2注射液

    我对使用 dropwizard 还很陌生 目前我正在尝试实现 HK2 依赖注入 这在资源内部工作得很好 但在资源外部却不起作用 这是我正在做的事情 Client client new JerseyClientBuilder environm
  • 输入特征以获得默认参数提升

    免责声明 我知道这个问题的答案 我认为这可能会引起一些普遍的兴趣 问题 我们怎样才能拥有一种类型特征 能够产生由执行而产生的类型默认参数促销 动机 我希望能够可移植地使用变量参数 例如 void foo char const fmt Ple
  • ASP MVC C#:是否可以将动态值传递到属性中?

    好吧 我对 C 很陌生 我正在尝试使用 ASP MVC2 创建一个小网站 我想创建我自己的授权属性 但如果可能的话 我需要传递一些值 例如 CustomAuthorize GroupID Method Parameter public Ac
  • 如何改进该 Java 代码以查找字符串中的子字符串?

    最近 我被要求提交一份工作问题的解决方案 Problem 在字符串中查找子字符串 Input Little star s deep dish pizza sure is fantastic Search deep dish pizza Ou
  • 对 x86 上 L1 缓存行的独占访问?

    如果有一个 64 字节的缓冲区被大量读 写 那么它很可能会保留在 L1 中 但有什么办法可以强制这种行为吗 例如 给予一个核心对这 64 字节的独占访问权限 并告诉它不要与其他核心或内存控制器同步数据 以便这 64 字节始终存在于一个核心的
  • “self”在 iOS 5.1 上的调试器中不可用

    我正在尝试调试在 iOS 5 1 下运行的问题 当我在出现错误的代码内的调试器中停止并尝试使用调试器打印某些内容时 我收到消息 错误 警告 在声称捕获的上下文中停止 Objective C 对象指针 但 self 不可用 假装我们 在一般背
  • IE 的 ajax (XDR) 响应不一致

    我正在从 iframe 发出 ajax 请求 该请求通过 IE 插件注入到每个页面上 我用的是IE跨域请求因为 jQuery 的 ajax 在 IE 上失败 这在 IE8 和 9 上的运行时间为 75 另外 25 xdr onload甚至不
  • 从 RPC 编码的 WSDL 生成 Java 客户端的最简单方法是什么

    我对 Web 服务的概念不熟悉 目前正在开发一个项目 需要通过 SOAP 从外部应用程序检索一些数据 该应用程序提供了 RPC 编码的 WSDL 目前 我发现由于 RPC 被取代 用 Java 为该服务创建客户端非常困难 到目前为止 我得到
  • 从 .NET 应用程序捕获控制台输出 (C#)

    如何从 NET 应用程序调用控制台应用程序并捕获控制台中生成的所有输出 请记住 我不想先将信息保存在文件中 然后重新列出 因为我希望实时接收它 使用以下命令可以很容易地实现这一点ProcessStartInfo RedirectStanda
  • SCRIPT、STYLE 和 LINK 元素上的类型属性是否仍然需要?

    您将看到许多网站具有以下类型的代码 脚本元素 链接元素 风格元素 我的问题是这样的 Are the type当今流行的浏览器需要哪些属性 通俗指 IE 8 Firefox Webkit Opera 和 Chrome 如果你会发生什么do n
  • 在 Android Service 类中哪里停止/销毁线程?

    我通过以下方式创建了线程服务 public class TCPClientService extends Service Override public void onCreate Measurements new LinkedList