【问题标题】:How to manage Loopers and Threads (thread doesn't die anymore!)如何管理 Loopers 和线程(线程不再死了!)
【发布时间】:2011-09-10 19:12:48
【问题描述】:

我创建了一个扩展 Thread 的类,以在非 UI 线程中通过 LocationManager 检索用户位置。我将其实现为一个线程,因为它必须根据请求启动并在有限的时间内完成它的工作。 顺便说一句,我必须在线程中添加一个 Looper 对象,以便能够为 LocationManager (onLocationChanged) 创建处理程序。

这是代码:

public class UserLocationThread extends Thread implements LocationListener {
//...
public void run() {
    try {
        Looper.prepare();
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
        Looper.loop();
        Looper.myLooper().quit();
    } catch (Exception e) {
        //...
    }
}

@Override
public void onLocationChanged(Location location) {
    locationManager.removeUpdates(this);
    //...
    handler.sendMessage(msg); //this is the handler for communication with father thread
}

//...}

我希望线程启动,接收用户位置数据(在这种情况下只是一次),通过消息将数据发送到主线程到处理程序,然后死亡。 问题是,在我的情况下,线程不再死亡,一旦 run 方法结束(应该没问题,否则 onLocationChanged 将不会收到新位置)。

但是以这种方式,假设线程的停止和挂起方法已被弃用,那么至少在这种情况下,使带有活套的线程死亡的好方法是什么?

提前致谢 ;)

【问题讨论】:

    标签: android multithreading handler looper


    【解决方案1】:

    您可以使用Handler 明确退出Looper 的循环:

    private Handler mUserLocationHandler = null;
    private Handler handler = null;
    
    public class UserLocationThread extends Thread implements LocationListener {    
    
     public void run() {
        try {
              Looper.prepare();
            mUserLocationHandler = new Handler();
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
            Looper.loop();
    
        } catch (Exception e) {
            //...
        }
    }
    
    
    @Override
    public void onLocationChanged(Location location) {
        locationManager.removeUpdates(this);
        //...
        handler.sendMessage(msg); 
        if(mUserLocationHandler != null){
            mUserLocationHandler.getLooper().quit();
        }
    }
    

    【讨论】:

    • 在我的例子中,“handler”是一个从调用线程传递给这个线程的 Handler 对象,用于将收集到的数据从一个传递到另一个。因此,我不能调用 handler.getLooper().quit(),因为它指的是活动线程,而不是 userLocationThread。注意 onLocationChanged 是在新线程里面,需要 Looper 让这个回调方法在 locationManager 接收到一个位置时被调用。
    • 当您调用 Looper.myLooper() 时,您将获得与当前线程关联的 Looper。当您调用 handler.getLooper() 时,您会得到与特定 handler 关联的 Looper
    • 但是如果handler关联同一个线程,返回的Looper应该是一样的吧?
    • 是的,如果您在调用Looper.myLooper() 的同一线程中创建handler,它们应该是相同的。
    • 哦,我明白你的意思了 :) 不,在你调用Looper.mylooper().loop() 之后,在你的原始代码中你调用Looper.myLooper().quit()loop() 函数不会返回,除非您调用 quit()。你打电话给quit() 之后 loop()。所以基本上,你永远不会到达你的 quit() 并最终进入无限 loop():)
    【解决方案2】:

    “我将其实现为一个踏板,因为它必须根据请求启动并在有限的时间内完成它的工作。”

    这听起来像是简单地重用主循环器的完美理由。没有必要在这里产生一个新的线程。如果您在 onLocationChanged() 中进行阻塞工作(网络 I/O 等),此时您可以启动 ASyncTask。

    在您的 Activity/Service 或其他任何东西上实现 LocationListener,并让它默认使用主循环器。

    没有必要生成一个新线程,将其设置为循环,然后立即退出。

    【讨论】:

      【解决方案3】:

      IntentService 很适合做这项工作。

      IntentService 是按需处理异步请求(表示为 Intent)的服务的基类。客户端通过 startService(Intent) 调用发送请求;服务根据需要启动,使用工作线程依次处理每个 Intent,并在工作结束时自行停止。

      【讨论】:

        【解决方案4】:

        Looper().quit();不错,按规范:

        导致 loop() 方法终止,不再处理消息队列中的任何消息。

        但是,如果您有一个正在处理的任务,并且您也想停止它,您可以获取工作线程并使其中断:

        @Override
        public void onLocationChanged(Location location) {
            locationManager.removeUpdates(this);
            handler.sendMessage(msg); //this is the handler for communication with father thread
            if(mUserLocationHandler != null){
                mUserLocationHandler.getLooper().quit();
                mUserLocationHandler.getLooper().getThread().interrupt(); // <-- here
            }
        

        }

        这适用于大多数 IO 和线程锁定/等待。

        【讨论】:

          【解决方案5】:

          扩展AsyncTask 类。它会自动为您完成所有线程和处理。

          【讨论】:

          • 我不认为AsyncTask 在这种情况下会起作用,因为线程必须有Looper 循环。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-08
          相关资源
          最近更新 更多