2011-12-31 19 views
34

Ứng dụng của tôi cần sửa chữa vị trí thường xuyên, ngay cả khi điện thoại không tỉnh táo. Để thực hiện việc này, tôi đang sử dụng IntentService với mẫu được cung cấp rộng rãi bởi Commonsware. https://github.com/commonsguy/cwac-wakefulGửi tin nhắn đến một Trình xử lý trên một chuỗi đã chết khi nhận được một vị trí từ một số IntentService

Để sửa vị trí, tôi dựa vào mã sau được cung cấp bởi thành viên có tên là Fedor. What is the simplest and most robust way to get the user's current location on Android?. Tôi hơi sửa đổi nó để trả về null thay vì nhận được vị trí cuối cùng được biết

Cả hai đều hoạt động hoàn hảo khi không kết hợp: Tôi có thể sửa vị trí từ lớp của Fedor trong Hoạt động và tôi có thể thực hiện một số nội dung cơ bản (như đăng nhập một cái gì đó) bằng cách sử dụng lớp Commonsware.

Sự cố xảy ra khi tôi đang cố gắng sửa lỗi vị trí từ lớp con WakefulIntentService của Commonsware. LocationListeners không phản ứng với locationUpdates và tôi nhận được những cảnh báo này (tôi chưa nhận được sự tinh tế của các chủ đề, trình xử lý, ...). Ai đó có thể giúp tôi hiểu vấn đề là gì không? Cảm ơn và tôi muốn tất cả các bạn một năm mới rất hạnh phúc :)

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) 

Đây là lớp con của tôi 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); 
} 

Và đây là một bản sao của lớp Fedor của (chút thay đổi: không cần GPS hay cuối cùng biết vị trí)

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); 

} 

}

Trả lời

33

Bạn không thể đăng ký một cách an toàn nghe từ một IntentService, khi số IntentService biến mất ngay sau khi onHandleIntent() (a.k.a., doWakefulWork()) hoàn tất. Thay vào đó, bạn sẽ cần sử dụng dịch vụ thông thường, cộng với các chi tiết xử lý như thời gian chờ (ví dụ: người dùng ở tầng hầm và không thể nhận tín hiệu GPS).

+1

Nó hoạt động như một nét duyên dáng! Cảm ơn bạn rất nhiều! Tôi đã thiết lập báo thức trong lớp con Ứng dụng của mình và tạo các phương thức startLocationPoll() và stopLocationPoll() tại đó. Chúc mừng năm mới! – znat

+0

khi tôi sử dụng ví dụ trên liên kết .... tôi đã nhận được ... "E/LocationPoller (442): Mục đích không hợp lệ - không có nhà cung cấp" ... bất kỳ đầu mối nào? – user836026

+1

@ user836026: Bạn không thể cung cấp thêm 'LocationPoller.EXTRA_PROVIDER' trên' Intent', cho biết nhà cung cấp nào sẽ sử dụng. Nếu bạn có thêm câu hỏi về thành phần này, vui lòng sử dụng nút "Đặt câu hỏi" thay vì đăng nhận xét tại đây. – CommonsWare

6

Đối với những người khác như tôi: Tôi gặp sự cố tương tự liên quan đến AsyncTask. Theo tôi hiểu, lớp đó giả định rằng nó được khởi tạo trên luồng UI (chính).

Một cách giải quyết (một trong những có thể) là đặt sau trong MyApplication lớp:

@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(); 
} 

(đừng quên đề cập đến nó trong AndroidManifest.xml:

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

)

12

Tôi đã có một tình huống tương tự, và tôi đã sử dụng thiết bị Android Looper để có hiệu quả tốt: http://developer.android.com/reference/android/os/Looper.html

cụ thể, ngay sau khi gọi hàm thiết lập người nghe, tôi gọi:

Looper.loop(); 

Đó khối xử lí hiện tại vì vậy nó không chết nhưng đồng thời cho phép nó xử lý các sự kiện, vì vậy bạn sẽ có cơ hội được thông báo khi người nghe của bạn được gọi. Một vòng lặp đơn giản sẽ ngăn bạn nhận được thông báo khi người nghe được gọi.

Và khi người nghe được gọi và tôi đang thực hiện xong việc xử lý dữ liệu của nó, tôi đặt:

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

Tôi cũng làm như vậy. Nhưng tôi thêm nếu (Looper.myLooper() == null) Looper.prepare(); trước Looper.loop(); –

+0

Tôi cũng chạy một chuỗi riêng biệt để hết thời gian chờ sau một thời gian cụ thể (5-15 giây cho mạng, 45-120 giây cho gps). Bởi vì nếu không Looper.loop() sẽ giữ cho thiết bị tỉnh táo mãi mãi. –

Các vấn đề liên quan