【问题标题】:IntentService : How to enqueue correctly?IntentService:如何正确入队?
【发布时间】:2011-10-15 12:52:04
【问题描述】:

在我的代码中,我使用IntentService 来收听位置更新(GPS 或网络更新),当收到事件时会触发此IntentService,因此它从任何活动中以startService() 开始.

public class AddLocationService extends IntentService implements LocationListener {
    /*My code here*/
}

    @Override
protected void onHandleIntent(Intent intent) {
    if(getOldLoc() == null) 
    { 
        //Get a new location
        this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TIME_INTERVAL_GPS, 0, this);
        this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_INTERVAL_GPS, 0, this);
        Log.d(AddLocationService.TAG, "Network listener started");

        this.time_start_listening = System.currentTimeMillis();
        mTimerThread mTimerRunnable = new mTimerThread();
        this.timerThread = new Thread(mTimerRunnable);
        this.timerThread.start();
    }
    else    
        /*REUSE OLD LOCATION*/
}

现在我的问题是:当两个事件启动 IntentService 并且第二个事件启动它而第一个事件仍在请求更新时,我希望第二个事件等到第一个事件完全完成(找到位置或计时器线程完成)。 但是,每当第二次执行 IntentService 时(第一个实例仍在运行),它会打印日志并按照并行执行的方式执行。

但是我认为IntentService 的主要目标是它是连续的,所以第二个意图必须等到第一个意图完成...

我是不是误会了什么?

【问题讨论】:

    标签: android service android-intent intentservice


    【解决方案1】:

    您的 onHandleIntent 方法似乎没有阻塞它正在执行的线程,因此它会快速返回并允许处理第二个意图。不仅如此,从 LocationManager 到该线程的任何回调都不太可能被处理,因为后台线程可能会在 onHandleIntent 完成时被杀死。

    如果您真的想使用 IntentService 来管理您的意图队列,那么您需要在自己的线程上进行位置处理,并在等待位置回调时将 IntentService 线程加入到位置线程。

    这里有一段代码演示了这个想法:

    public class TestService extends IntentService {
        private static final String TAG = "TestService";
    
        private Location mLocation = null;
    
        public TestService() {
           super(TAG);
        }
    
        @Override
        public void onHandleIntent(Intent intent) {
            Log.d(TAG, "onHandleIntent");
    
            if (mLocation == null) {
                Log.d(TAG, "launching location thread");
                LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    
                LocationThread thread = new LocationThread(locationManager);
                thread.start();
                try {
                    thread.join(10000);
                } catch (InterruptedException e) {
                    Log.d(TAG, "timeout");
                    return;
                }
    
                Log.d(TAG, "join finished, loc="+mLocation.toString());
            } else {
                 Log.d(TAG, "using existing loc="+mLocation.toString());
            }
        }
    
        private class LocationThread extends Thread implements LocationListener  {
            private LocationManager locationManager = null;
    
            public LocationThread(LocationManager locationManager) {
                super("UploaderService-Uploader");
                this.locationManager = locationManager;
            }
    
            @Override
            public void run() {
                Log.d(TAG, "Thread.run");
                Looper.prepare();
               this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
                this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    
                Looper.loop();
            }
    
            @Override
            public void onLocationChanged(Location location) {
                // TODO Auto-generated method stub
                Log.d(TAG, "onLocationChanged("+location.toString()+")");
                mLocation = location;
                Looper.myLooper().quit();
             }
    
             @Override
             public void onProviderDisabled(String arg0) {
             }
    
             @Override
             public void onProviderEnabled(String arg0) {
             }
    
             @Override
             public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
             }
    
       }
    }
    

    有趣的是 Looper 在线程上运行消息循环(以允许处理回调)。

    考虑到使用 IntentService 执行此操作所需的工作量,可能值得研究从 Service 派生并管理您自己的意图队列。

    【讨论】:

    • 嘿@Rob,感谢您的回复。当您说onHandleIntent 方法没有阻塞线程时,您能否更具体一点?我应该怎么做才能阻止它?从另一个活动创建意图时与标志有关还是我应该在 onHandleIntent() 方法中做的事情?
    • 编辑:我想我明白你的意思:我的 IntentService 在仍然请求更新的同时返回。我怎样才能阻止它。两人wait() - notify() 会是个好主意吗?
    • 有点,我已经更新了我的答案,提供了有关如何修复它的更多信息
    • 也可以直接在 IntentService 后台线程上使用 Looper,但我有点紧张,因为我不确定它是否会对 IntentService 管理排队。
    【解决方案2】:

    onHandleIntent 已经在它自己的线程中了。你不(不应该)在那里创作。这一切都由 IntentService 为您处理。

    【讨论】:

      【解决方案3】:

      感谢一百万,这正是我处理位置请求所需要的。 谢谢你的解释,让我明白,我对所有的looper概念都不是很熟悉,现在我更好地理解了!

      如果有人需要同样的东西,如果您的位置线程没有自然停止(join(millis) 的时间结束),请不要忘记停止线程循环器,方法是在onHandleIntent() 中添加:

                      if(thread.isAlive())
                      {
                          thread.onThreadStop();
                          try{
                              thread.interrupt();
                          }catch (Exception e) {
                              Log.d(TAG, "Exception on interrupt: " + e.getMessage());
                          }
                      }   
      

      thread.join(yourTime) 之后,例如,如果您没有找到任何位置更新,您仍然会在一段时间后停止线程。以及方法onThreadStop()

                      /*We remove location updates here and stop the looper*/
                      public void onThreadStop()
                      {
                          this.locationManager1.removeUpdates(this);
                          handleLocationChange(AddLocationService.this.currentBestLocation);
                          Looper.myLooper().quit();
                      }
      

      但是,我认为我在第一次运行此代码时看到了我的两个意图被处理,但现在当我有多个意图同时仍然请求位置更新时,只有第一个被处理。 我的方法onHandleIntent() 似乎执行正确,在指定的时间后停止线程,甚至显示最后一个日志(方法的最后一条语句),但第二个意图没有执行...... 你知道为什么吗?

      【讨论】:

      • 经过几次测试后,我注意到只有在某些情况下(当我调用thread.interrupt(),即时间到期时)线程仍在运行,这可能就是为什么下一个意图不是治疗。但是,当线程正常完成时,线程确实完全停止(thread.isAlive() 返回 false)并且我的下一个意图被发送。所以我的问题是:如何正确停止我的线程,和/或为什么在使用thread.interrupt() 时它没有停止??
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-02
      • 1970-01-01
      • 1970-01-01
      • 2017-02-25
      相关资源
      最近更新 更多