ปัญหา:
การรับตำแหน่งปัจจุบันของผู้ใช้ภายในขีด จำกัด ASAP และในเวลาเดียวกันก็ประหยัดแบตเตอรี่
ทำไมปัญหาเป็นปัญหา:
ก่อนอื่น Android มีผู้ให้บริการสองราย เครือข่ายและ GPS บางครั้งเครือข่ายดีกว่าและบางครั้ง GPS ก็ดีกว่า
โดย "ดีกว่า" ฉันหมายถึงอัตราส่วนความเร็วกับความแม่นยำ
ฉันยินดีที่จะเสียสละความแม่นยำเพียงไม่กี่เมตรถ้าฉันสามารถหาที่ตั้งได้เกือบจะทันทีและไม่ต้องเปิด GPS
ประการที่สองถ้าคุณขอให้อัปเดตสำหรับการเปลี่ยนแปลงตำแหน่งจะไม่มีการส่งอะไรเลยหากตำแหน่งปัจจุบันมีเสถียรภาพ
Google มีตัวอย่างของการระบุตำแหน่ง "ดีที่สุด" ที่นี่: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
แต่ฉันคิดว่ามันไม่ได้อยู่ใกล้ที่ดีเท่าที่ควร /อาจจะเป็น.
ฉันสับสนเพราะเหตุใด google จึงไม่ได้ API ตามปกติสำหรับสถานที่นักพัฒนาไม่ควรสนใจว่าสถานที่นั้นมาจากที่ใดคุณควรระบุสิ่งที่คุณต้องการและโทรศัพท์ควรเลือกให้คุณ
สิ่งที่ฉันต้องการความช่วยเหลือ:
ฉันต้องการหาวิธีที่ดีในการระบุตำแหน่ง "ที่ดีที่สุด" บางทีอาจจะมีบางฮิวริสติกหรืออาจผ่านห้องสมุดบุคคลที่สาม
นี่ไม่ได้หมายความว่าเป็นผู้ให้บริการที่ดีที่สุด!
ฉันอาจจะใช้ผู้ให้บริการทั้งหมดและเลือกสิ่งที่ดีที่สุด
พื้นหลังของแอพ:
แอพจะรวบรวมตำแหน่งของผู้ใช้ในช่วงเวลาที่กำหนด (ให้บอกทุก ๆ 10 นาที) แล้วส่งไปที่เซิร์ฟเวอร์
แอปควรประหยัดแบตเตอรี่ให้มากที่สุดและตำแหน่งควรมีความแม่นยำระดับ X (50-100?)
เป้าหมายคือในภายหลังสามารถพล็อตเส้นทางของผู้ใช้ในระหว่างวันบนแผนที่ดังนั้นฉันต้องการความแม่นยำที่เพียงพอสำหรับสิ่งนั้น
อื่น ๆ:
คุณคิดว่าอะไรคือคุณค่าที่สมเหตุสมผลสำหรับความถูกต้องที่ต้องการและเป็นที่ยอมรับ?
ฉันใช้ 100m เป็นที่ยอมรับและ 30m ตามที่ต้องการนี่เป็นการถามมากมายหรือไม่?
ฉันต้องการที่จะสามารถวางแผนเส้นทางของผู้ใช้บนแผนที่ในภายหลัง
100m สำหรับความต้องการและ 500m สำหรับการยอมรับที่ดีขึ้น?
นอกจากนี้ตอนนี้ฉันมี GPS เปิดสูงสุด 60 วินาทีต่อการอัปเดตตำแหน่งมันสั้นเกินไปที่จะรับตำแหน่งถ้าคุณอยู่ในอาคารที่มีความแม่นยำ 200m หรือไม่
นี่คือรหัสปัจจุบันของฉันข้อเสนอแนะใด ๆ ที่ชื่นชม (นอกเหนือจากการขาดการตรวจสอบข้อผิดพลาดซึ่งเป็นสิ่งที่ต้องทำ):
protected void runTask() {
final LocationManager locationManager = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER));
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
if (getLocationQuality(bestLocation) != LocationQuality.GOOD) {
Looper.prepare();
setLooper(Looper.myLooper());
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
updateBestLocation(location);
if (getLocationQuality(bestLocation) != LocationQuality.GOOD)
return;
// We're done
Looper l = getLooper();
if (l != null) l.quit();
}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
Log.i("LocationCollector", "Fail");
Looper l = getLooper();
if (l != null) l.quit();
}
};
// Register the listener with the Location Manager to receive
// location updates
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000, 1, locationListener,
Looper.myLooper());
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1,
locationListener, Looper.myLooper());
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
Looper l = getLooper();
if (l != null) l.quit();
// Log.i("LocationCollector",
// "Stopping collector due to timeout");
}
}, MAX_POLLING_TIME);
Looper.loop();
t.cancel();
locationManager.removeUpdates(locationListener);
setLooper(null);
}
if (getLocationQuality(bestLocation) != LocationQuality.BAD)
sendUpdate(locationToString(bestLocation));
else Log.w("LocationCollector", "Failed to get a location");
}
private enum LocationQuality {
BAD, ACCEPTED, GOOD;
public String toString() {
if (this == GOOD) return "Good";
else if (this == ACCEPTED) return "Accepted";
else return "Bad";
}
}
private LocationQuality getLocationQuality(Location location) {
if (location == null) return LocationQuality.BAD;
if (!location.hasAccuracy()) return LocationQuality.BAD;
long currentTime = System.currentTimeMillis();
if (currentTime - location.getTime() < MAX_AGE
&& location.getAccuracy() <= GOOD_ACCURACY)
return LocationQuality.GOOD;
if (location.getAccuracy() <= ACCEPTED_ACCURACY)
return LocationQuality.ACCEPTED;
return LocationQuality.BAD;
}
private synchronized void updateBestLocation(Location location) {
bestLocation = getBestLocation(location, bestLocation);
}
// Pretty much an unmodified version of googles example
protected Location getBestLocation(Location location,
Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return location;
}
if (location == null) return currentBestLocation;
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return location;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return currentBestLocation;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and
// accuracy
if (isMoreAccurate) {
return location;
} else if (isNewer && !isLessAccurate) {
return location;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
return location;
}
return bestLocation;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}