2011-04-25 36 views
37

我一直在這個問題上停留了很長時間。我正在研究一個應用程序,它在幾個不同的活動中使用相當廣泛的位置。我找到的每個示例都在每個活動中使用一個單獨的LocationListener。這在我的情況下是不可行的。Android - 跨多個活動實施LocationListener的最佳方法

我想知道在多個活動中跟蹤用戶位置的最有效方式是什麼。現在我創建了一個實現LocationListener的服務,並使用廣播來更新Activity基類中的靜態lat和long字段。這意味着服務始終在運行,這並不理想。但是,如果我關閉服務並僅在需要時重新啓動服務,則需要時間才能獲得良好的位置。我需要活動的onCreate()中的位置數據。如果我嘗試在活動基類中實現它,情況也是如此。如果我不斷在onResume/onCreate中註冊監聽器,並在onPause()中取消註冊,則需要花費太多時間才能開始接收更新。我也嘗試創建一個我可以綁定的服務,因此只有在需要位置時纔會啓動。但是我有同樣的問題,綁定到服務並開始獲取更新需要很長時間。

我正在使用的服務現在可以使用,但是從我讀過的所有內容中,我不應該使用一個持續運行的服務來處理這樣的瑣事。但應用程序的全部重點是根據用戶的當前位置提供相關數據。所以我有一個只在後臺運行並定期提供更新的服務。在這一點上導致我重新審視設計的一個主要問題是,我最近發現,如果用戶在未打開GPS的情況下啓動應用程序並隨後啓用onProviderEnabled(),則不會調用onProviderEnabled()。在這種情況下,應用程序無法識別GPS已啓用,因此它可以開始監聽更新。

我以爲我通過查看示例瞭解LocationManager和LocationListener,但似乎無法將其應用於需要多個活動中的位置數據的情況。任何幫助或建議將不勝感激。

回答

43

我通常會實現此要求的方式是使用綁定的Service實現,如SDK文檔中的Local Service Sample中的實現。顯然,您熟悉服務的優勢,只允許您創建一次所有的位置代碼。

通過綁定訪問服務允許服務啓動和停止自己,使其在應用程序不在前臺時不會運行(只要沒有更多活動被綁定,它就會死亡)。 IMO做好這項工作的關鍵是將onStart()和UNBIND中的服務綁定到onStop(),因爲當您從一個活動移動到另一個活動時,這兩個呼叫會重疊(第二個活動在第一個活動停止之前開始)。這樣可以防止服務在應用程序內部移動時死亡,並且只會在整個應用程序(或至少對位置感興趣的任何部分)離開前臺時讓服務死亡。

使用綁定,您不必在廣播中傳遞位置數據,因爲活動可以直接在服務上調用方法以獲取最新位置。但是,作爲指示新的更新何時可用的方法,廣播仍然是有利的...但是這只是成爲收聽活動的通知者以調用服務上的getLocation()方法。

我的$ 0.02。希望有助於!

+0

我一直在這條路上,但我不知道onStart和onStop重疊。這對我很有吸引力,我會嘗試一下,讓你知道我明天想出了什麼。謝謝! – d370urn3ur 2011-04-25 22:28:37

+1

只是想知道,這將關閉屏幕如何工作?在屏幕打開/關閉的同時打開/關閉onPause()onResume()和UNBIND上的服務綁定以及在活動切換時工作是明智的嗎? – 2011-06-23 19:29:55

+2

@Grantland有效的點,因爲活動仍然是前臺服務將生活。如果服務需要在這些情況下將自己調整回來,我會保持綁定相同,但是爲'Intent.ACTION_SCREEN_ON'和'Intent.ACTION_SCREEN_OFF'註冊一個'BroadcastReceiver'來關閉像GPS這樣重的組件。將綁定機制移入onPause()/ onResume()會導致服務在整個應用程序的使用過程中可能會停止/重新啓動,因爲這些回調不會重疊,從而使服務經常處於未綁定狀態。 – Devunwired 2011-09-08 18:48:27

0

你可以讓你的服務把你的緯度長的座標寫到一個sqlite數據庫上,這樣你就沒有服務綁定的開銷,你的座標可以在你所有的活動中被訪問。

也許在您的主要活動中,您可以檢查GPS狀態,如果它被關閉,您可以提示用戶啓用它。一旦GPS啓用啓動您的服務。

14

我得到了同樣的問題,我嘗試用Devunwired的很好的答案來解決它,但我有一些麻煩。我找不到停止服務的方法,當我完成我的應用時,GPS模塊仍在運行。所以,我發現了另一種方式:

我寫了一個GPS.java類:

public class GPS { 

    private IGPSActivity main; 

    // Helper for GPS-Position 
    private LocationListener mlocListener; 
    private LocationManager mlocManager; 

    private boolean isRunning; 

    public GPS(IGPSActivity main) { 
     this.main = main; 

     // GPS Position 
     mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE); 
     mlocListener = new MyLocationListener(); 
     mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener); 
     // GPS Position END 
     this.isRunning = true; 
    } 

    public void stopGPS() { 
     if(isRunning) { 
      mlocManager.removeUpdates(mlocListener); 
      this.isRunning = false; 
     } 
    } 

    public void resumeGPS() { 
     mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener); 
     this.isRunning = true; 
    } 

    public boolean isRunning() { 
     return this.isRunning; 
    } 

    public class MyLocationListener implements LocationListener { 

     private final String TAG = MyLocationListener.class.getSimpleName(); 

     @Override 
     public void onLocationChanged(Location loc) { 
      GPS.this.main.locationChanged(loc.getLongitude(), loc.getLatitude()); 
     } 

     @Override 
     public void onProviderDisabled(String provider) { 
      GPS.this.main.displayGPSSettingsDialog(); 
     } 

     @Override 
     public void onProviderEnabled(String provider) { 

     } 

     @Override 
     public void onStatusChanged(String provider, int status, Bundle extras) { 

     } 

    } 

} 

這個類是在每一個需要它的GPS座標活動中使用。每一項活動必須實現以下接口(需要通信):

public interface IGPSActivity { 
    public void locationChanged(double longitude, double latitude); 
    public void displayGPSSettingsDialog(); 
} 

現在我的主要活動看起來像這樣:

public class MainActivity extends Activity implements IGPSActivity { 

    private GPS gps; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     gps = new GPS(this); 
    } 


    @Override 
    protected void onResume() { 
     if(!gps.isRunning()) gps.resumeGPS(); 
     super.onResume(); 
    } 

    @Override 
    protected void onStop() { 
     gps.stopGPS(); 
     super.onStop(); 
    } 


    public void locationChanged(double longitude, double latitude) { 
     Log.d(TAG, "Main-Longitude: " + longitude); 
     Log.d(TAG, "Main-Latitude: " + latitude); 
    } 


    @Override 
    public void displayGPSSettingsDialog() { 
       Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 
       startActivity(intent); 
    } 
} 

,第二個這樣的:

public class TEST4GPS extends Activity implements IGPSActivity{ 

    private GPS gps; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     this.gps = new GPS(this); 
    } 

    @Override 
    public void locationChanged(double longitude, double latitude) { 
     Log.d("TEST", "Test-Longitude: " + longitude); 
     Log.d("TEST", "Test-Latitude: " + latitude); 

    } 

    @Override 
    protected void onResume() { 
     if(!gps.isRunning()) gps.resumeGPS(); 
     super. onResume(); 
    } 

    @Override 
    protected void onStop() { 
     gps.stopGPS(); 
     super.onStop(); 
    } 

    @Override 
    public void displayGPSSettingsDialog() { 
       Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 
       startActivity(intent); 

    } 
} 

它不像Devunwired的解決方案一樣美麗,但它適用於我。 CYA

+0

喜歡你的解決方案!我做了一些改進,並且工作得很好!謝謝。 – 2013-06-29 14:55:45

+0

@Spipau,我喜歡你的答案。我試過了,但它不適合我。任何機會,你可以看看我的代碼,看看你能弄清楚我做錯了什麼? http://stackoverflow.com/questions/29771717/android-gps-not-working-for-me – MrGibbage 2015-04-21 12:47:59

+2

@MrGibbage對不起,但我將不得不重新創建整個事情。我的答案現在已經3年了,如果我不得不在我的應用程序中再次實施全球GPS信號,它看起來會完全不同。將跟蹤代碼放入您的應用程序中,並使用LocalBroadcastManager將位置發送到您選擇的活動/片段。 https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html – Spipau 2015-04-22 09:40:29

-1

這是一個非常簡單和直接的方式做到這一點:

在您的主要活動:

private boolean mFinish; 

@Override 
public void onBackPressed() { 
    mFinish = true; 
} 


@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    mFinish = false; 
    ... 
} 

@Override 
public void onPause(){ 
    super.onPause(); 
    if (mFinish) { 
     // remove updates here 
     mLocationManager.removeUpdates(mLocationListener); 
    } 
} 

如果按回到你的主要活動這隻會刪除更新監聽器,但以其他方式繼續。

這不是最好的辦法,但它是一個簡單的複製粘貼解決方案。

確保在調用位置偵聽器時(例如在屏幕上旋轉時)不要調用位置偵聽器,否則最終會在後臺運行多個偵聽器。

+0

Downvoters:介意添加一個解釋爲什麼? – lenooh 2017-07-15 16:51:01