2011-12-31 56 views
34

即使手機沒有喚醒,我的應用程序也需要定期進行定位。 爲此,我使用IntentService和Commonsware慷慨提供的模式。 https://github.com/commonsguy/cwac-wakeful從IntentService獲取位置時,將消息發送到處理程序的處理程序

要獲得位置修復,我依靠由名爲Fedor的成員提供的以下代碼。 What is the simplest and most robust way to get the user's current location on Android?。我稍微修改它以返回null而不是獲取最後一個已知位置

它們在未組合時都可以很好地工作:我可以在Activity中獲得Fedor類的位置修復,並且可以執行一些基本的操作東西)使用Commonsware類。

當我試圖從Commonsware的WakefulIntentService子類中獲取位置修復程序時,會出現此問題。 LocationListeners對locationUpdates沒有反應,我得到了這些警告(我還沒有得到線程,處理程序的微妙之處......)。有人能幫我理解問題是什麼嗎?謝謝,祝大家新年快樂:)

12-31 14:09:33.664: W/MessageQueue(3264): Handler (android.location.LocationManager$ListenerTransport$1) {41403330} sending message to a  Handler on a dead thread 
12-31 14:09:33.664: W/MessageQueue(3264): java.lang.RuntimeException: Handler (android.location.LocationManager$ListenerTransport$1) {41403330} sending message to a Handler on a dead thread 
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:196) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessageAtTime(Handler.java:473) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessageDelayed(Handler.java:446) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessage(Handler.java:383) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.location.LocationManager$ListenerTransport.onLocationChanged(LocationManager.java:193) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.location.ILocationListener$Stub.onTransact(ILocationListener.java:58) 
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Binder.execTransact(Binder.java:338) 
12-31 14:09:33.664: W/MessageQueue(3264): at dalvik.system.NativeStart.run(Native Method) 

這是我WakefulIntentService子類:

public class AppService extends WakefulIntentService { 
public static final String TAG = "AppService"; 
public AppService() { 
    super("AppService"); 
} 

public LocationResult locationResult = new LocationResult() { 
    @Override 
    public void gotLocation(final Location location) { 
     if (location == null) 
      Log.d(TAG, "location could not be retrieved"); 
     else 
      sendMessage(location); 
    } 
}; 

@Override 
protected void doWakefulWork(Intent intent) { 
    PhoneLocation myLocation; 
    myLocation = new PhoneLocation(); 
    myLocation.getLocation(getApplicationContext(), locationResult); 
} 

在這裏,費多爾的類的副本(略作修改:無需GPS,也沒有最後的已知位置)

public class PhoneLocation { 
public static String TAG = "MyLocation"; 
Timer timer1; 
LocationManager lm; 
LocationResult locationResult; 
boolean gps_enabled=false; 
boolean network_enabled=false; 

public boolean getLocation(Context context, LocationResult result) 
{ 
    //I use LocationResult callback class to pass location value from MyLocation to user code. 
    locationResult=result; 
    if(lm==null) lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 

    //exceptions will be thrown if provider is not permitted. 
    try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){} 
    try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){} 

    //don't start listeners if no provider is enabled 
    if(!gps_enabled && !network_enabled) 
     return false; 

    if(network_enabled) lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork); 

    timer1=new Timer(); 
    timer1.schedule(new ReturnNullLocation(), 20000); 
    return true; 
} 

LocationListener locationListenerNetwork = new LocationListener() { 
    public void onLocationChanged(Location location) { 
     timer1.cancel(); 
     locationResult.gotLocation(location); 
     lm.removeUpdates(this); 
    } 
    public void onProviderDisabled(String provider) {} 
    public void onProviderEnabled(String provider) {} 
    public void onStatusChanged(String provider, int status, Bundle extras) {} 
}; 

class ReturnNullLocation extends TimerTask { 
    @Override 
    public void run() { 
      lm.removeUpdates(locationListenerNetwork); 
      locationResult.gotLocation(null); 
    } 
} 

public static abstract class LocationResult{ 
    public abstract void gotLocation(Location location); 

} 

}

回答

33

你不能安全地從註冊監聽器,IntentService一旦onHandleIntent()(又名,doWakefulWork())就完成了。相反,您需要使用常規服務,以及處理超時等詳細信息(例如用戶位於地下室並且無法獲取GPS信號)。

+1

它的工作原理就像一個魅力!非常感謝! 我已經在我的應用程序子類中設置了警報,並在那裏創建了startLocationPoll()和stopLocationPoll()方法。新年快樂! – znat 2012-01-01 19:46:31

+0

當我使用鏈接上的例子....我得到了......「E/LocationPoller(442):無效的意圖 - 沒有提供者」...請任何線索? – user836026 2012-07-29 13:47:29

+1

@ user836026:您無法在'Intent'上提供額外的'LocationPoller.EXTRA_PROVIDER',表明要使用哪個提供程序。如果您對此組件有其他疑問,請使用「Ask Question」按鈕,而不是在此發佈評論。 – CommonsWare 2012-07-29 14:30:35

6

對於像我這樣的其他人:我有類似的問題與AsyncTask有關。據我所知,該類假定它在UI(主)線程上初始化。

一種解決方法(幾個可能的一個)是將按照MyApplication類:

@Override 
public void onCreate() { 
    // workaround for http://code.google.com/p/android/issues/detail?id=20915 
    try { 
     Class.forName("android.os.AsyncTask"); 
    } catch (ClassNotFoundException e) {} 
    super.onCreate(); 
} 

(不要忘記提及它在AndroidManifest.xml

<application 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:name="MyApplication" 
    > 

12

我遇到過類似的情況,並且我使用了Android Looper工具來取得良好效果: http://developer.android.com/reference/android/os/Looper.html

具體,只是調用該函數建立監聽後,我打電話:

Looper.loop(); 

阻止當前線程,這樣它就不會死,但在同一時間讓它處理事件,所以你當你的聽衆被叫時,你將有機會得到通知。一個簡單的循環會阻止你在監聽器被調用時得到通知。

而當監聽器被調用和我做處理其數據,我把:

Looper.myLooper().quit(); 
+1

我也這麼做。但我添加if(Looper.myLooper()== null)Looper.prepare();在Looper.loop()之前; – 2013-12-02 14:40:28

+0

我也運行一個單獨的線程超時一段時間後(網絡5-15秒,gps 45-120秒)。否則,Looper.loop()會使設備永遠保持清醒狀態。 – 2013-12-02 14:54:27

相關問題