2011-07-28 70 views
5

在我的代碼中,我使用的是IntentService來偵聽位置更新(GPS或網絡更新),並且在收到事件時觸發此IntentService,因此它將從startService()開始從任何活動開始。IntentService:如何正確排隊?

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和第二啓動它,而第一個是仍然要求更新,我會想第二個要等到第一種是完全完成(位置找到OR定時器線程完成)。 但是,無論何時第二次執行IntentService(第一個實例仍在運行),它都會打印日誌並按照並行執行的方式執行。

不過我認爲的IntentService的主要目標是,它是什麼順序所以第二意圖將不得不等待,直到第一個做...

難道我missunderstood的東西嗎?

回答

3

看來你的onHandleIntent方法沒有阻塞它正在執行的線程,所以它會很快返回並允許第二個intent被處理。不僅如此,從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) { 
     } 

    } 
} 

有趣的是在那裏是運行的線程上的消息循環彎針(允許回調的處理)。

鑑於使用IntentService執行此操作所需的努力,可能需要調查派生自Service的內容並管理您自己的意圖隊列。

+0

嗨@Rob,謝謝你的回覆。 當你說'onHandleIntent'方法沒有阻塞線程時,你可以更具體嗎?我應該怎麼做才能阻止它? 從另一個活動創建意圖時,它與Flags有關嗎?還是我應該在'onHandleIntent()'方法中做的事情? – Pom12

+0

編輯:我想我明白你的意思:我的IntentService返回時仍然請求更新。 我怎樣才能阻止它。這個二人組「wait() - notify()」是個好主意嗎? – Pom12

+0

類型,我更新了我的答案,並提供了更多關於如何修復它的信息 – Rob

2

onHandleIntent已經在它自己的線程中。你不(不應該)在那裏創造。這一切都由IntentService爲您處理。

1

感謝一百萬,這正是我需要處理位置請求。 謝謝你的解釋,並且對我來說很清楚,我並不是很熟悉所有的looper概念,現在我明白了!

萬一有人需要這樣的事情,不要忘記停止線程尺蠖,如果你的位置線程沒有在onHandleIntent()自然停止(時間在join(millis)結束),加入這樣的:

   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()似乎正確執行,在指定的時間後停止線程,甚至顯示最後一個日誌(方法的最後一個語句),但第二個目標未執行... 你知道爲什麼嗎?

+0

經過幾次測試後,我注意到在某些情況下(僅當我調用'thread.interrupt()'時,即時間過期),線程仍然在最後運行,這可能是爲什麼不處理下一個intent。 但是,當線程正常完成時,線程會完全停止('thread.isAlive()'返回false),併發送下一個intent。 所以我的問題將是:如何正確地停止我的線程,和/或爲什麼不使用'thread.interrupt()'時停止? – Pom12