Masalah:
Mendapatkan lokasi pengguna saat ini dalam ambang ASAP dan pada saat yang sama menghemat baterai.
Mengapa masalahnya adalah masalah:
Pertama, Android memiliki dua penyedia; jaringan dan GPS. Terkadang jaringan lebih baik dan terkadang GPS lebih baik.
Dengan "lebih baik" Maksudku rasio kecepatan vs akurasi.
Saya bersedia mengorbankan akurasi beberapa meter jika saya bisa mendapatkan lokasi hampir instan dan tanpa menyalakan GPS.
Kedua, jika Anda meminta pembaruan untuk perubahan lokasi tidak dikirim jika lokasi saat ini stabil.
Google memiliki contoh untuk menentukan lokasi "terbaik" di sini: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Tapi saya pikir tidak ada yang sedekat yang seharusnya. /bisa jadi.
Saya agak bingung mengapa google belum memiliki API yang dinormalisasi untuk lokasi, pengembang tidak perlu peduli dari mana lokasi itu berasal, Anda hanya perlu menentukan apa yang Anda inginkan dan telepon harus memilih untuk Anda.
Apa yang saya perlu bantuan:
Saya perlu menemukan cara yang baik untuk menentukan lokasi "terbaik", mungkin melalui beberapa heuristik atau mungkin melalui beberapa perpustakaan pihak ke-3.
Ini tidak berarti menentukan penyedia terbaik!
Saya mungkin akan menggunakan semua penyedia dan memilih yang terbaik dari mereka.
Latar belakang aplikasi:
Aplikasi ini akan mengumpulkan lokasi pengguna pada interval yang tetap (misalkan setiap 10 menit atau lebih) dan mengirimkannya ke server.
Aplikasi ini harus menghemat baterai sebanyak mungkin dan lokasi harus memiliki akurasi X (50-100?) Meter.
Tujuannya adalah untuk nantinya dapat memplot jalur pengguna pada siang hari di peta jadi saya perlu akurasi yang cukup untuk itu.
Lain-lain:
Menurut Anda apa nilai yang masuk akal pada akurasi yang diinginkan dan diterima?
Saya telah menggunakan 100m sebagai diterima dan 30m seperti yang diinginkan, apakah ini banyak bertanya?
Saya ingin dapat memplot jalur pengguna di peta nanti.
Apakah 100m untuk yang diinginkan dan 500m untuk diterima lebih baik?
Juga, saat ini saya memiliki GPS aktif selama maksimum 60 detik per pembaruan lokasi, apakah ini terlalu pendek untuk mendapatkan lokasi jika Anda berada di dalam ruangan dengan akurasi mungkin 200m?
Ini adalah kode saya saat ini, ada umpan balik yang dihargai (terlepas dari kurangnya pengecekan kesalahan yaitu TODO):
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);
}
sumber
Jawaban:
Sepertinya kami sedang mengkode aplikasi yang sama ;-)
Ini adalah implementasi saya saat ini. Saya masih dalam tahap pengujian beta aplikasi pengunggah GPS saya, jadi mungkin ada banyak kemungkinan perbaikan. tetapi sejauh ini tampaknya bekerja dengan cukup baik.
Sunting: di sini adalah bagian yang meminta pembaruan berkala dari penyedia lokasi:
Hal yang perlu dipertimbangkan:
jangan terlalu sering meminta pembaruan GPS, itu menghabiskan daya baterai. Saat ini saya menggunakan 30 menit sebagai default untuk aplikasi saya.
tambahkan cek 'jarak minimum ke lokasi terakhir yang diketahui'. tanpa ini, poin Anda akan "melompat-lompat" ketika GPS tidak tersedia dan lokasi sedang triangulasi dari menara sel. atau Anda dapat memeriksa apakah lokasi baru di luar nilai akurasi dari lokasi terakhir yang diketahui.
sumber
Untuk memilih penyedia lokasi yang tepat untuk aplikasi Anda, Anda dapat menggunakan objek Kriteria :
Baca dokumentasi untuk requestLocationUpdates untuk detail lebih lanjut tentang bagaimana argumen diperhitungkan:
Lebih banyak pemikiran
Criteria.ACCURACY_HIGH
kriteria harus memberikan kesalahan di bawah 100m, yang tidak sebaik GPS dapat, tetapi sesuai dengan kebutuhan Anda.sumber
Criteria
tetapi bagaimana jika lokasi jaringan terbaru luar biasa (mungkin tahu melalui wifi) dan tidak membutuhkan waktu atau baterai untuk mendapatkannya (getLastKnown), maka kriteria mungkin akan mengabaikan itu dan mengembalikan GPS sebagai gantinya. Saya tidak percaya Google telah mempersulit pengembang.Menjawab dua poin pertama :
GPS akan selalu memberi Anda lokasi yang lebih tepat, jika diaktifkan dan tidak ada dinding tebal di sekitarnya .
Jika lokasi tidak berubah, maka Anda dapat memanggil getLastKnownLocation (String) dan mengambil lokasi segera.
Menggunakan pendekatan alternatif :
Anda dapat mencoba menggunakan id sel atau semua sel tetangga
Anda dapat merujuk lokasi sel melalui beberapa database terbuka (mis., Http://www.location-api.com/ atau http://opencellid.org/ )
Strateginya adalah membaca daftar ID menara saat membaca lokasi. Kemudian, dalam kueri berikutnya (10 menit di aplikasi Anda), baca lagi. Jika setidaknya beberapa menara sama, maka aman digunakan
getLastKnownLocation(String)
. Jika tidak, maka tungguonLocationChanged()
. Ini menghindari kebutuhan database pihak ketiga untuk lokasi. Anda juga dapat mencoba pendekatan ini .sumber
Ini solusi saya yang bekerja cukup baik:
sumber
Akurasi lokasi sebagian besar tergantung pada penyedia lokasi yang digunakan:
Jika akurasi yang Anda cari, maka GPS adalah satu-satunya pilihan Anda.
Saya telah membaca artikel yang sangat informatif tentang hal ini di sini .
Adapun batas waktu GPS - 60 detik harus cukup, dan dalam kebanyakan kasus bahkan terlalu banyak. Saya pikir 30 detik tidak apa-apa dan kadang-kadang bahkan kurang dari 5 detik ...
jika Anda hanya memerlukan satu lokasi, saya sarankan dalam
onLocationChanged
metode Anda , setelah Anda menerima pembaruan Anda akan membatalkan registrasi pendengar dan menghindari penggunaan GPS yang tidak perlu.sumber
Saat ini saya menggunakan karena ini dapat dipercaya untuk mendapatkan lokasi dan menghitung jarak untuk aplikasi saya ...... saya menggunakan ini untuk aplikasi taksi saya.
menggunakan fusion API yang telah dikembangkan oleh pengembang google dengan fusi GPS Sensor, Magnetometer, Accelerometer juga menggunakan Wifi atau lokasi sel untuk menghitung atau memperkirakan lokasi. Itu juga dapat memberikan pembaruan lokasi juga di dalam gedung secara akurat. untuk detail dapatkan tautan https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
sumber
Saya menjelajahi internet untuk jawaban yang diperbarui (tahun lalu) menggunakan metode penarikan lokasi terbaru yang disarankan oleh google (untuk menggunakan FusedLocationProviderClient). Saya akhirnya mendarat di ini:
https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates
Saya membuat proyek baru dan menyalin sebagian besar kode ini. Ledakan. Berhasil. Dan saya pikir tanpa garis yang usang.
Selain itu, simulator tampaknya tidak mendapatkan lokasi GPS, yang saya tahu. Itu memang sejauh melaporkan ini di log: "Semua pengaturan lokasi puas."
Dan akhirnya, jika Anda ingin tahu (saya tahu), Anda TIDAK perlu kunci peta google api dari konsol pengembang google, jika semua yang Anda inginkan adalah lokasi GPS.
Juga bermanfaat adalah tutorial mereka. Tapi saya ingin contoh tutorial / kode satu halaman penuh, dan itu. Tumpukan tutorial mereka tetapi membingungkan ketika Anda baru dengan ini karena Anda tidak tahu apa yang Anda butuhkan dari halaman sebelumnya.
https://developer.android.com/training/location/index.html
Dan akhirnya, ingat hal-hal seperti ini:
Saya tidak hanya harus memodifikasi mainActivity.Java. Saya juga harus memodifikasi Strings.xml, androidmanifest.xml, DAN build.gradle yang benar. Dan juga activity_Main.xml Anda (tetapi bagian itu mudah bagi saya).
Saya perlu menambahkan dependensi seperti ini: implementasi 'com.google.android.gms: play-services-location: 11.8.0', dan perbarui pengaturan SDK studio android saya untuk memasukkan layanan google play. (pengaturan file, pengaturan tampilan sistem, android SDK, SDK Tools, memeriksa layanan google play).
pembaruan: simulator android tampaknya mendapatkan lokasi dan perubahan lokasi acara (ketika saya mengubah nilai dalam pengaturan sim). Tetapi hasil terbaik dan pertama saya pada perangkat yang sebenarnya. Jadi mungkin paling mudah untuk menguji pada perangkat yang sebenarnya.
sumber
Baru-baru ini refactored untuk mendapatkan lokasi kode, mempelajari beberapa ide bagus, dan akhirnya mencapai perpustakaan dan Demo yang relatif sempurna.
@Gryphius jawabannya bagus
Implementasi lengkap: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
1.Terima kasih solusi ide @Gryphius, saya juga berbagi kode lengkap.
2. Setiap permintaan untuk menyelesaikan lokasi, yang terbaik adalah menghapus Pembaruan, jika tidak, bilah status telepon akan selalu menampilkan ikon posisi
sumber
Dalam pengalaman saya, saya telah menemukan yang terbaik untuk memperbaiki GPS kecuali itu tidak tersedia. Saya tidak tahu banyak tentang penyedia lokasi lain, tetapi saya tahu bahwa untuk GPS ada beberapa trik yang dapat digunakan untuk memberikan sedikit ukuran presisi ghetto. Ketinggian sering merupakan tanda, sehingga Anda dapat memeriksa nilai-nilai konyol. Ada ukuran akurasi pada perbaikan lokasi Android. Juga jika Anda dapat melihat jumlah satelit yang digunakan, ini juga dapat menunjukkan ketepatan.
Cara yang menarik untuk mendapatkan ide yang lebih baik tentang keakuratan bisa dengan meminta satu set perbaikan dengan sangat cepat, seperti ~ 1 / detik selama 10 detik dan kemudian tidur selama satu atau dua menit. Satu pembicaraan saya telah menyebabkan percaya bahwa beberapa perangkat android akan melakukan ini. Anda kemudian akan menyingkirkan outlier (saya pernah mendengar filter Kalman disebutkan di sini) dan menggunakan semacam strategi pemusatan untuk mendapatkan satu perbaikan.
Jelas kedalaman Anda sampai di sini tergantung pada seberapa keras persyaratan Anda. Jika Anda memiliki persyaratan ketat untuk mendapatkan lokasi TERBAIK, saya pikir Anda akan menemukan bahwa lokasi GPS dan jaringan sama seperti apel dan jeruk. GPS juga bisa sangat berbeda dari satu perangkat ke perangkat lainnya.
sumber
Skyhook (http://www.skyhookwireless.com/) memiliki penyedia lokasi yang jauh lebih cepat daripada standar yang disediakan Google. Mungkin itu yang Anda cari. Saya tidak berafiliasi dengan mereka.
sumber