Android में उपयोगकर्ता का स्थान प्राप्त करने का अच्छा तरीका


211

समस्या:

एक थ्रेसहोल्ड ASAP के भीतर उपयोगकर्ता की वर्तमान स्थिति प्राप्त करना और उसी समय बैटरी का संरक्षण।

क्यों समस्या एक समस्या है:

सबसे पहले, android में दो प्रदाता हैं; नेटवर्क और जीपीएस। कभी नेटवर्क बेहतर होता है तो कभी जीपीएस बेहतर होता है।

"बेहतर" से मेरा मतलब है गति बनाम सटीकता अनुपात।
मैं सटीकता में कुछ मीटर का त्याग करने को तैयार हूं, अगर मैं जीपीएस को चालू किए बिना लगभग तुरंत स्थान प्राप्त कर सकता हूं।

दूसरे, यदि आप स्थान परिवर्तन के लिए अद्यतन का अनुरोध करते हैं तो वर्तमान स्थान स्थिर होने पर कुछ भी नहीं भेजा जाता है।

Google के पास "सर्वश्रेष्ठ" स्थान निर्धारित करने का एक उदाहरण है: http://developer.android.com/guide/topics/location/obtain-user-location.html#BestEstimate
लेकिन मुझे लगता है कि यह वह जगह नहीं है जहां पर उतना अच्छा होना चाहिए जितना कि " /हो सकता है।

मुझे भ्रम है कि Google ने स्थान के लिए सामान्यीकृत API क्यों नहीं बनाया है, डेवलपर को यह ध्यान नहीं रखना चाहिए कि स्थान कहाँ से है, आपको बस यह निर्दिष्ट करना चाहिए कि आप क्या चाहते हैं और फ़ोन को आपके लिए चुनना चाहिए।

मुझे क्या मदद चाहिए:

मुझे "सर्वश्रेष्ठ" स्थान निर्धारित करने के लिए एक अच्छा तरीका खोजने की आवश्यकता है, शायद कुछ हेयुरिस्टिक या शायद कुछ 3 पार्टी लाइब्रेरी के माध्यम से।

इसका मतलब यह नहीं है कि सबसे अच्छा प्रदाता निर्धारित करें!
मैं शायद सभी प्रदाताओं का उपयोग करने जा रहा हूँ और उनमें से सबसे अच्छा चुन रहा हूँ।

एप्लिकेशन की पृष्ठभूमि:

एप्लिकेशन एक निश्चित अंतराल पर उपयोगकर्ता के स्थान को इकट्ठा करेगा (प्रत्येक 10 मिनट या तो कहने दें) और इसे एक सर्वर पर भेज दें।
एप्लिकेशन को यथासंभव बैटरी का संरक्षण करना चाहिए और स्थान पर एक्स (50-100?) मीटर की सटीकता होनी चाहिए।

लक्ष्य बाद में एक नक्शे पर दिन के दौरान उपयोगकर्ता के मार्ग की साजिश रचने में सक्षम है, इसलिए मुझे उसके लिए पर्याप्त सटीकता की आवश्यकता है।

विविध:

आपको क्या लगता है कि वांछित और स्वीकृत सटीकता पर उचित मूल्य हैं?
मैं के रूप में स्वीकार किए जाते हैं और वांछित के रूप में 30 मीटर का उपयोग कर रहा हूँ, यह पूछने के लिए बहुत कुछ है?
मैं बाद में एक मानचित्र पर उपयोगकर्ता के पथ को प्लॉट करने में सक्षम होना चाहता हूं।
क्या वांछित के लिए 100 मी और बेहतर के लिए 500 मी है?

इसके अलावा, अभी मेरे पास अधिकतम 60 सेकंड प्रति स्थान अपडेट के लिए GPS है, क्या यह स्थान पाने के लिए बहुत छोटा है यदि आप 200 मी की सटीकता के साथ घर के अंदर हैं?


यह मेरा वर्तमान कोड है, किसी भी प्रतिक्रिया की सराहना की जाती है (त्रुटि जाँच की कमी के अलावा जो 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);
}

7
वास्तव में देर से, लेकिन हाल ही में IO 2013 में घोषित "फ़्यूस्ड लोकेशन प्रोवाइडर" की तरह लग रहा है कि यह आपकी कई जरूरतों को पूरा करता है - डेवलपर.
मैट

getBestLocation की अंतिम पंक्ति () नहीं होनी चाहिए: currentBestLocation लौटें; बदले में सबसे अच्छा लाभ;
गवरील

जवाबों:


164

लगता है कि हम उसी एप्लिकेशन को कोड कर रहे हैं ;-)
यहाँ मेरा वर्तमान कार्यान्वयन है। मैं अभी भी अपने जीपीएस अपलोडर ऐप के बीटा परीक्षण चरण में हूं, इसलिए कई संभावित सुधार हो सकते हैं। लेकिन यह अब तक बहुत अच्छा काम करता है।

/**
 * try to get the 'best' location selected from all providers
 */
private Location getBestLocation() {
    Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER);
    Location networkLocation =
            getLocationByProvider(LocationManager.NETWORK_PROVIDER);
    // if we have only one location available, the choice is easy
    if (gpslocation == null) {
        Log.d(TAG, "No GPS Location available.");
        return networkLocation;
    }
    if (networkLocation == null) {
        Log.d(TAG, "No Network Location available");
        return gpslocation;
    }
    // a locationupdate is considered 'old' if its older than the configured
    // update interval. this means, we didn't get a
    // update from this provider since the last check
    long old = System.currentTimeMillis() - getGPSCheckMilliSecsFromPrefs();
    boolean gpsIsOld = (gpslocation.getTime() < old);
    boolean networkIsOld = (networkLocation.getTime() < old);
    // gps is current and available, gps is better than network
    if (!gpsIsOld) {
        Log.d(TAG, "Returning current GPS Location");
        return gpslocation;
    }
    // gps is old, we can't trust it. use network location
    if (!networkIsOld) {
        Log.d(TAG, "GPS is old, Network is current, returning network");
        return networkLocation;
    }
    // both are old return the newer of those two
    if (gpslocation.getTime() > networkLocation.getTime()) {
        Log.d(TAG, "Both are old, returning gps(newer)");
        return gpslocation;
    } else {
        Log.d(TAG, "Both are old, returning network(newer)");
        return networkLocation;
    }
}

/**
 * get the last known location from a specific provider (network/gps)
 */
private Location getLocationByProvider(String provider) {
    Location location = null;
    if (!isProviderSupported(provider)) {
        return null;
    }
    LocationManager locationManager = (LocationManager) getApplicationContext()
            .getSystemService(Context.LOCATION_SERVICE);
    try {
        if (locationManager.isProviderEnabled(provider)) {
            location = locationManager.getLastKnownLocation(provider);
        }
    } catch (IllegalArgumentException e) {
        Log.d(TAG, "Cannot acces Provider " + provider);
    }
    return location;
}

संपादित करें: यहां वह भाग है जो स्थान प्रदाताओं से आवधिक अपडेट का अनुरोध करता है:

public void startRecording() {
    gpsTimer.cancel();
    gpsTimer = new Timer();
    long checkInterval = getGPSCheckMilliSecsFromPrefs();
    long minDistance = getMinDistanceFromPrefs();
    // receive updates
    LocationManager locationManager = (LocationManager) getApplicationContext()
            .getSystemService(Context.LOCATION_SERVICE);
    for (String s : locationManager.getAllProviders()) {
        locationManager.requestLocationUpdates(s, checkInterval,
                minDistance, new LocationListener() {

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

                    @Override
                    public void onProviderEnabled(String provider) {}

                    @Override
                    public void onProviderDisabled(String provider) {}

                    @Override
                    public void onLocationChanged(Location location) {
                        // if this is a gps location, we can use it
                        if (location.getProvider().equals(
                                LocationManager.GPS_PROVIDER)) {
                            doLocationUpdate(location, true);
                        }
                    }
                });
        // //Toast.makeText(this, "GPS Service STARTED",
        // Toast.LENGTH_LONG).show();
        gps_recorder_running = true;
    }
    // start the gps receiver thread
    gpsTimer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            Location location = getBestLocation();
            doLocationUpdate(location, false);
        }
    }, 0, checkInterval);
}

public void doLocationUpdate(Location l, boolean force) {
    long minDistance = getMinDistanceFromPrefs();
    Log.d(TAG, "update received:" + l);
    if (l == null) {
        Log.d(TAG, "Empty location");
        if (force)
            Toast.makeText(this, "Current location not available",
                    Toast.LENGTH_SHORT).show();
        return;
    }
    if (lastLocation != null) {
        float distance = l.distanceTo(lastLocation);
        Log.d(TAG, "Distance to last: " + distance);
        if (l.distanceTo(lastLocation) < minDistance && !force) {
            Log.d(TAG, "Position didn't change");
            return;
        }
        if (l.getAccuracy() >= lastLocation.getAccuracy()
                && l.distanceTo(lastLocation) < l.getAccuracy() && !force) {
            Log.d(TAG,
                    "Accuracy got worse and we are still "
                      + "within the accuracy range.. Not updating");
            return;
        }
        if (l.getTime() <= lastprovidertimestamp && !force) {
            Log.d(TAG, "Timestamp not never than last");
            return;
        }
    }
    // upload/store your location here
}

विचार करने के लिए बातें:

  • अक्सर जीपीएस अपडेट का अनुरोध न करें, इससे बैटरी की शक्ति कम हो जाती है। मैं वर्तमान में अपने आवेदन के लिए डिफ़ॉल्ट रूप में 30 मिनट का उपयोग करता हूं।

  • 'अंतिम ज्ञात स्थान के लिए न्यूनतम दूरी' चेक जोड़ें। इसके बिना, आपके अंक जीपीएस के उपलब्ध नहीं होने पर "चारों ओर छलांग" लगाएंगे और सेल टावरों से स्थान को त्रिकोणित किया जा रहा है। या आप यह जान सकते हैं कि नया स्थान अंतिम ज्ञात स्थान से सटीकता मूल्य के बाहर है या नहीं।


2
आपको वास्तव में एक ताजा स्थान कभी नहीं मिलता है, आप केवल उन स्थानों का उपयोग करते हैं जो पिछले अपडेट से होते हैं। मुझे लगता है कि यह कोड वास्तव में एक श्रोता को जोड़कर बहुत लाभान्वित करेगा जो समय-समय पर जीपीएस को चालू करके स्थान को अपडेट करता है।
निकलैस ए।

2
क्षमा करें, मुझे लगा कि आप केवल उस हिस्से में रुचि रखते हैं जो सभी उपलब्ध स्थानों से सर्वश्रेष्ठ का चयन करता है। मैंने ऊपर दिए गए कोड को इन अनुरोधों के साथ जोड़ा है। यदि कोई नया जीपीएस स्थान प्राप्त होता है, तो उसे तुरंत संग्रहीत / अपलोड किया जाता है। यदि मुझे एक नेटवर्क स्थान अपडेट प्राप्त होता है, तो मैं इसे संदर्भ के लिए संग्रहीत करता हूं और 'आशा' करता हूं कि मैं एक जीपीएस अपडेट प्राप्त करूंगा और जब तक कि अगला स्थान जांच न हो जाए।
ग्रिफियस

2
मेरे पास एक स्टॉपर रिकॉर्डिंग () विधि भी थी जिसने टाइमर को रद्द कर दिया। मैंने अंततः एक टाइमर से एक शेड्यूल्डड्रेडपूल एक्ज़ीक्यूटर पर स्विच किया, इसलिए स्टॉपर रिकॉर्डिंग अब मूल रूप से निष्पादक (शटडाउन) और सभी लोकेशन अपडेट श्रोताओं को पंजीकृत करता है
Gryphius

1
मेरे scm के अनुसार, stopRecording ने केवल gpsTimer.cancel () और gps_recos_running = false सेट किया, इसलिए जैसे आपके मामले में, श्रोताओं का कोई सफाई नहीं है। वर्तमान कोड एक वेक्टर में सभी सक्रिय श्रोताओं का ट्रैक रखता है, जब 1.5 साल पहले मैंने यह उत्तर लिखा था तो मेरे पास यह नहीं था।
ग्रिफियस

1
यह पहले से ही गिटब पर है , लेकिन मुझे यकीन नहीं है कि यह अभी भी जीपीएस सामान करने का सबसे अच्छा तरीका है। जब से मैंने यह कोड लिखा है, Afaik ने स्थान API में कई सुधार किए हैं।
ग्रिएफियस

33

अपने एप्लिकेशन के लिए सही स्थान प्रदाता का चयन करने के लिए, आप मानदंड वस्तुओं का उपयोग कर सकते हैं :

Criteria myCriteria = new Criteria();
myCriteria.setAccuracy(Criteria.ACCURACY_HIGH);
myCriteria.setPowerRequirement(Criteria.POWER_LOW);
// let Android select the right location provider for you
String myProvider = locationManager.getBestProvider(myCriteria, true); 

// finally require updates at -at least- the desired rate
long minTimeMillis = 600000; // 600,000 milliseconds make 10 minutes
locationManager.requestLocationUpdates(myProvider,minTimeMillis,0,locationListener); 

तर्क को ध्यान में रखते हुए अधिक विवरण के लिए requestLocationUpdates के दस्तावेज़ पढ़ें :

अधिसूचना की आवृत्ति को मिनिमेट और मिनिस्ट्रेशन मापदंडों का उपयोग करके नियंत्रित किया जा सकता है। यदि मिनिमम टाइम 0 से अधिक है, तो पावर मैनेज करने के लिए लोकेशन मैनजर को लोकेशन अपडेट के बीच मिनिमम मिलीसेकंड के लिए आराम दे सकता है। यदि minDistance 0 से अधिक है, तो एक स्थान केवल तब प्रसारित किया जाएगा जब डिवाइस minDistance मीटर से चलता है। जितनी बार संभव हो सूचनाएं प्राप्त करने के लिए, दोनों मापदंडों को 0 पर सेट करें।

अधिक विचार

  • आप स्थान ऑब्जेक्ट्स की सटीकता Location.getAccuracy () के साथ देख सकते हैं , जो मीटर में स्थिति की अनुमानित सटीकता लौटाता है।
  • Criteria.ACCURACY_HIGHकसौटी 100 मीटर नीचे आप त्रुटियों देना चाहिए, के रूप में जीपीएस हो सकता है जो अच्छा के रूप में नहीं है, लेकिन अपनी आवश्यकताओं से मेल खाता है।
  • आपको उपयोगकर्ता द्वारा अनुपलब्ध या अक्षम होने पर अपने स्थान प्रदाता की स्थिति पर नज़र रखने और किसी अन्य प्रदाता पर स्विच करने की भी आवश्यकता है।
  • निष्क्रिय प्रदाता भी आवेदन के इस प्रकार के लिए एक अच्छा मैच हो सकता है: विचार जब भी वे किसी अन्य ऐप्स और प्रसारण प्रणाली में से अनुरोध है कि वे स्थान अपडेट उपयोग करने के लिए है।

मैंने देखा है, Criteriaलेकिन अगर नवीनतम नेटवर्क स्थान भयानक है (यह वाईफ़ाई के माध्यम से पता हो सकता है) और इसे प्राप्त करने में कोई समय या बैटरी नहीं लगती है (getLastKnown), तो मानदंड शायद इसकी उपेक्षा करेंगे और इसके बजाय जीपीएस को वापस कर देंगे। मुझे विश्वास नहीं हो रहा है कि Google ने इसे डेवलपर्स के लिए मुश्किल बना दिया है।
निकलैस ए।

मानदंड का उपयोग करने के शीर्ष पर, आप अपने द्वारा चुने गए प्रदाता द्वारा भेजे गए प्रत्येक स्थान अपडेट में, जीपीएस प्रदाता के लिए lastKnowLocation की जांच कर सकते हैं और इसकी (सटीकता और तारीख) अपने वर्तमान स्थान से तुलना कर सकते हैं। लेकिन यह मुझे आपके विनिर्देशों से एक आवश्यकता के बजाय एक अच्छा-सा लगता है; यदि कभी-कभी कुछ बेहतर सटीकता हासिल की जाती है, तो क्या यह वास्तव में आपके उपयोगकर्ताओं के लिए उपयोगी होगा?
स्टीफन

यही कारण है कि मैं अब कर रहा हूँ, समस्या यह है कि मैं एक कठिन समय है अगर अंतिम पता काफी अच्छा है। मैं यह भी जोड़ सकता हूं कि मुझे खुद को एक प्रदाता तक सीमित नहीं करना है, जितना अधिक मैं तेजी से उपयोग करूंगा मुझे ताला मिल सकता है।
निकलस ए।

ध्यान रखें कि PASSIVE_PROVIDER को API स्तर 8 या उच्चतर की आवश्यकता होती है।
एडुआर्डो

@ स्टीफन को संपादन के लिए खेद है। इसका ध्यान न रखें। आपकी पोस्ट सही है। मैंने वह त्रुटि के लिए संपादित किया था। माफ़ करना। सादर।
गौचो

10

पहले दो बिंदुओं का उत्तर देना :

  • जीपीएस हमेशा आपको एक अधिक सटीक स्थान देगा, यदि यह सक्षम है और यदि चारों ओर मोटी दीवारें नहीं हैं

  • यदि स्थान नहीं बदला, तो आप getLastKnownLocation (स्ट्रिंग) को कॉल कर सकते हैं और तुरंत स्थान पुनः प्राप्त कर सकते हैं ।

एक वैकल्पिक दृष्टिकोण का उपयोग करना :

आप उपयोग में या सभी पड़ोसी कोशिकाओं में सेल आईडी प्राप्त करने का प्रयास कर सकते हैं

TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
GsmCellLocation loc = (GsmCellLocation) mTelephonyManager.getCellLocation(); 
Log.d ("CID", Integer.toString(loc.getCid()));
Log.d ("LAC", Integer.toString(loc.getLac()));
// or 
List<NeighboringCellInfo> list = mTelephonyManager.getNeighboringCellInfo ();
for (NeighboringCellInfo cell : list) {
    Log.d ("CID", Integer.toString(cell.getCid()));
    Log.d ("LAC", Integer.toString(cell.getLac()));
}

फिर आप कई खुले डेटाबेस (जैसे, http://www.location-api.com/ या http://opencellid.org/ ) के माध्यम से सेल स्थान का उल्लेख कर सकते हैं


स्थान पढ़ते समय टॉवर आईडी की सूची को पढ़ने की रणनीति होगी। फिर, अगली क्वेरी में (आपके ऐप में 10 मिनट), उन्हें फिर से पढ़ें। यदि कम से कम कुछ टॉवर समान हैं, तो इसका उपयोग करना सुरक्षित है getLastKnownLocation(String)। यदि वे नहीं हैं, तो प्रतीक्षा करें onLocationChanged()। यह स्थान के लिए तीसरे पक्ष के डेटाबेस की आवश्यकता से बचा जाता है। आप इस दृष्टिकोण को भी आजमा सकते हैं ।


हाँ, लेकिन मुझे समस्या आती है अगर lastKnownLocation वास्तव में खराब है। मुझे दो स्थानों में से सबसे अच्छा निर्णय लेने का एक अच्छा तरीका चाहिए।
निकलैस ए।

आप टावरों की जानकारी संग्रहीत कर सकते हैं और जांच सकते हैं कि क्या उन टावरों को बदल दिया गया है। यदि उन्होंने किया है, तो एक नए स्थान की प्रतीक्षा करें, यदि नहीं (या यदि केवल कुछ बदला हुआ है), तो इसका पुन: उपयोग करें। इस तरह से आप टॉवर स्थानों की तुलना डेटाबेस से करने से बचते हैं।
अलिदम

टावरों का उपयोग करना मेरे लिए एक बड़ा ओवरकिल जैसा लगता है, हालांकि अच्छा विचार है।
निकलैस ए।

@Nicklas कोड से अधिक जटिल नहीं है। हालाँकि आपको android.anifest.permission # ACCESS_COARSE_UPDATES की आवश्यकता होगी।
अलिदम

हाँ, लेकिन मुझे अभी भी एक तृतीय पक्ष सेवा का उपयोग करने की आवश्यकता है और मुझे यह भी तय करने की आवश्यकता है कि स्थान डेटा पर टॉवर जानकारी को उपयोगकर्ता के लिए कब करना है, यह सिर्फ जटिलता की एक अतिरिक्त परत जोड़ देता है।
निकलेस ए।

9

यह मेरा समाधान है जो काफी अच्छी तरह से काम करता है:

private Location bestLocation = null;
private Looper looper;
private boolean networkEnabled = false, gpsEnabled = false;

private synchronized void setLooper(Looper looper) {
    this.looper = looper;
}

private synchronized void stopLooper() {
    if (looper == null) return;
    looper.quit();
}

@Override
protected void runTask() {
    final LocationManager locationManager = (LocationManager) service
            .getSystemService(Context.LOCATION_SERVICE);
    final SharedPreferences prefs = getPreferences();
    final int maxPollingTime = Integer.parseInt(prefs.getString(
            POLLING_KEY, "0"));
    final int desiredAccuracy = Integer.parseInt(prefs.getString(
            DESIRED_KEY, "0"));
    final int acceptedAccuracy = Integer.parseInt(prefs.getString(
            ACCEPTED_KEY, "0"));
    final int maxAge = Integer.parseInt(prefs.getString(AGE_KEY, "0"));
    final String whichProvider = prefs.getString(PROVIDER_KEY, "any");
    final boolean canUseGps = whichProvider.equals("gps")
            || whichProvider.equals("any");
    final boolean canUseNetwork = whichProvider.equals("network")
            || whichProvider.equals("any");
    if (canUseNetwork)
        networkEnabled = locationManager
                .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    if (canUseGps)
        gpsEnabled = locationManager
                .isProviderEnabled(LocationManager.GPS_PROVIDER);
    // If any provider is enabled now and we displayed a notification clear it.
    if (gpsEnabled || networkEnabled) removeErrorNotification();
    if (gpsEnabled)
        updateBestLocation(locationManager
                .getLastKnownLocation(LocationManager.GPS_PROVIDER));
    if (networkEnabled)
        updateBestLocation(locationManager
                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
    if (desiredAccuracy == 0
            || getLocationQuality(desiredAccuracy, acceptedAccuracy,
                    maxAge, bestLocation) != LocationQuality.GOOD) {
        // Define a listener that responds to location updates
        LocationListener locationListener = new LocationListener() {

            public void onLocationChanged(Location location) {
                updateBestLocation(location);
                if (desiredAccuracy != 0
                        && getLocationQuality(desiredAccuracy,
                                acceptedAccuracy, maxAge, bestLocation)
                                == LocationQuality.GOOD)
                    stopLooper();
            }

            public void onProviderEnabled(String provider) {
                if (isSameProvider(provider,
                        LocationManager.NETWORK_PROVIDER))networkEnabled =true;
                else if (isSameProvider(provider,
                        LocationManager.GPS_PROVIDER)) gpsEnabled = true;
                // The user has enabled a location, remove any error
                // notification
                if (canUseGps && gpsEnabled || canUseNetwork
                        && networkEnabled) removeErrorNotification();
            }

            public void onProviderDisabled(String provider) {
                if (isSameProvider(provider,
                        LocationManager.NETWORK_PROVIDER))networkEnabled=false;
                else if (isSameProvider(provider,
                        LocationManager.GPS_PROVIDER)) gpsEnabled = false;
                if (!gpsEnabled && !networkEnabled) {
                    showErrorNotification();
                    stopLooper();
                }
            }

            public void onStatusChanged(String provider, int status,
                    Bundle extras) {
                Log.i(LOG_TAG, "Provider " + provider + " statusChanged");
                if (isSameProvider(provider,
                        LocationManager.NETWORK_PROVIDER)) networkEnabled = 
                        status == LocationProvider.AVAILABLE
                        || status == LocationProvider.TEMPORARILY_UNAVAILABLE;
                else if (isSameProvider(provider,
                        LocationManager.GPS_PROVIDER))
                    gpsEnabled = status == LocationProvider.AVAILABLE
                      || status == LocationProvider.TEMPORARILY_UNAVAILABLE;
                // None of them are available, stop listening
                if (!networkEnabled && !gpsEnabled) {
                    showErrorNotification();
                    stopLooper();
                }
                // The user has enabled a location, remove any error
                // notification
                else if (canUseGps && gpsEnabled || canUseNetwork
                        && networkEnabled) removeErrorNotification();
            }
        };
        if (networkEnabled || gpsEnabled) {
            Looper.prepare();
            setLooper(Looper.myLooper());
            // Register the listener with the Location Manager to receive
            // location updates
            if (canUseGps)
                locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER, 1000, 1,
                        locationListener, Looper.myLooper());
            if (canUseNetwork)
                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER, 1000, 1,
                        locationListener, Looper.myLooper());
            Timer t = new Timer();
            t.schedule(new TimerTask() {

                @Override
                public void run() {
                    stopLooper();
                }
            }, maxPollingTime * 1000);
            Looper.loop();
            t.cancel();
            setLooper(null);
            locationManager.removeUpdates(locationListener);
        } else // No provider is enabled, show a notification
        showErrorNotification();
    }
    if (getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge,
            bestLocation) != LocationQuality.BAD) {
        sendUpdate(new Event(EVENT_TYPE, locationToString(desiredAccuracy,
                acceptedAccuracy, maxAge, bestLocation)));
    } else Log.w(LOG_TAG, "LocationCollector failed to get a location");
}

private synchronized void showErrorNotification() {
    if (notifId != 0) return;
    ServiceHandler handler = service.getHandler();
    NotificationInfo ni = NotificationInfo.createSingleNotification(
            R.string.locationcollector_notif_ticker,
            R.string.locationcollector_notif_title,
            R.string.locationcollector_notif_text,
            android.R.drawable.stat_notify_error);
    Intent intent = new Intent(
            android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
    ni.pendingIntent = PendingIntent.getActivity(service, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    Message msg = handler.obtainMessage(ServiceHandler.SHOW_NOTIFICATION);
    msg.obj = ni;
    handler.sendMessage(msg);
    notifId = ni.id;
}

private void removeErrorNotification() {
    if (notifId == 0) return;
    ServiceHandler handler = service.getHandler();
    if (handler != null) {
        Message msg = handler.obtainMessage(
                ServiceHandler.CLEAR_NOTIFICATION, notifId, 0);
        handler.sendMessage(msg);
        notifId = 0;
    }
}

@Override
public void interrupt() {
    stopLooper();
    super.interrupt();
}

private String locationToString(int desiredAccuracy, int acceptedAccuracy,
        int maxAge, Location location) {
    StringBuilder sb = new StringBuilder();
    sb.append(String.format(
            "qual=%s time=%d prov=%s acc=%.1f lat=%f long=%f",
            getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge,
                    location), location.getTime() / 1000, // Millis to
                                                            // seconds
            location.getProvider(), location.getAccuracy(), location
                    .getLatitude(), location.getLongitude()));
    if (location.hasAltitude())
        sb.append(String.format(" alt=%.1f", location.getAltitude()));
    if (location.hasBearing())
        sb.append(String.format(" bearing=%.2f", location.getBearing()));
    return sb.toString();
}

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(int desiredAccuracy,
        int acceptedAccuracy, int maxAge, Location location) {
    if (location == null) return LocationQuality.BAD;
    if (!location.hasAccuracy()) return LocationQuality.BAD;
    long currentTime = System.currentTimeMillis();
    if (currentTime - location.getTime() < maxAge * 1000
            && location.getAccuracy() <= desiredAccuracy)
        return LocationQuality.GOOD;
    if (acceptedAccuracy == -1
            || location.getAccuracy() <= acceptedAccuracy)
        return LocationQuality.ACCEPTED;
    return LocationQuality.BAD;
}

private synchronized void updateBestLocation(Location location) {
    bestLocation = getBestLocation(location, bestLocation);
}

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

हाय निकलैस मैं एक ही समान है तो क्या मैं किसी भी तरह से आपसे संवाद कर सकता हूं .. अगर आप हमारी मदद कर सकते हैं तो मैं आपको धन्यवाद देता हूं ..
स्कूल बॉय

क्या आप पूरा कोड पोस्ट कर सकते हैं? धन्यवाद, वास्तव में सराहना की
रॉडी

यह सभी कोड है। मेरे पास प्रोजेक्ट तक कोई पहुंच नहीं है।
निकल्स ए।

1
आपको लगता है कि इस प्रोजेक्ट का कोड "android-protips-location" है और यह अभी भी जीवित है। लोग देख सकते हैं कि यह यहां कैसे काम करता है। code.google.com/p/android-protips-location/source/browse/trunk/…
Gödel77

7

स्थान सटीकता ज्यादातर उपयोग किए गए स्थान प्रदाता पर निर्भर करती है:

  1. GPS - आपको कई मीटर सटीकता प्राप्त होगी (यह मानते हुए कि आपके पास GPS रिसेप्शन है)
  2. वाईफ़ाई - आप कुछ सौ मीटर सटीकता प्राप्त करेंगे
  3. सेल नेटवर्क - आपको बहुत गलत परिणाम मिलेंगे (मैंने 4 किमी तक विचलन देखा है ...)

यदि यह सटीकता है जिसकी आप तलाश कर रहे हैं, तो GPS आपके लिए एकमात्र विकल्प है।

मैंने इसके बारे में एक बहुत जानकारीपूर्ण लेख यहाँ पढ़ा है

जीपीएस टाइमआउट के लिए - 60 सेकंड पर्याप्त होना चाहिए, और ज्यादातर मामलों में बहुत अधिक। मुझे लगता है कि 30 सेकंड ठीक है और कभी-कभी 5 सेकंड से भी कम ...

यदि आपको केवल एक ही स्थान की आवश्यकता है, तो मेरा सुझाव है कि अपनी onLocationChangedविधि में, एक बार जब आप एक अपडेट प्राप्त करेंगे तो आप श्रोता की उपेक्षा करेंगे और GPS के अनावश्यक उपयोग से बचें।


मुझे वास्तव में परवाह नहीं है कि मैं अपना स्थान कहाँ से प्राप्त करूँ, मैं मुझे एक प्रदाता तक सीमित नहीं रखना चाहता हूँ
निकल्स ए।

आप डिवाइस पर उपलब्ध सभी स्थान प्रदाताओं को पंजीकृत कर सकते हैं (आप LocationManager.getProviders ()) से सभी प्रदाताओं की सूची प्राप्त कर सकते हैं, लेकिन यदि आप एक सटीक फिक्स की तलाश कर रहे हैं, तो ज्यादातर मामलों में नेटवर्क प्रदाता आपके लिए उपयोगी नहीं होगा।
मुज़िकांत

हाँ, लेकिन यह प्रदाताओं के बीच चयन के बारे में एक सवाल नहीं है, यह आम तौर पर सर्वोत्तम स्थान प्राप्त करने के बारे में एक सवाल है (यहां तक ​​कि जब कई प्रदाता शामिल हैं)
निकल्स ए।

4

वर्तमान में मैं इसका उपयोग कर रहा हूं क्योंकि यह स्थान पाने के लिए विश्वसनीय है और मेरे आवेदन के लिए दूरी की गणना करता है ...... मैं अपने टैक्सी एप्लिकेशन के लिए इसका उपयोग कर रहा हूं।

संलयन एपीआई का उपयोग करें कि Google डेवलपर ने जीपीएस सेंसर, मैग्नेटोमीटर, एक्सेलेरोमीटर के संलयन के साथ विकसित किया है, स्थान की गणना या अनुमान लगाने के लिए वाईफ़ाई या सेल स्थान का उपयोग कर रहा है। यह बिल्डिंग के अंदर भी लोकेशन अपडेट देने में सक्षम है। विस्तार के लिए लिंक https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi पर जाएं

import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class MainActivity extends Activity implements LocationListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final long ONE_MIN = 500;
    private static final long TWO_MIN = 500;
    private static final long FIVE_MIN = 500;
    private static final long POLLING_FREQ = 1000 * 20;
    private static final long FASTEST_UPDATE_FREQ = 1000 * 5;
    private static final float MIN_ACCURACY = 1.0f;
    private static final float MIN_LAST_READ_ACCURACY = 1;

    private LocationRequest mLocationRequest;
    private Location mBestReading;
TextView tv;
    private GoogleApiClient mGoogleApiClient;

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

        if (!servicesAvailable()) {
            finish();
        }

        setContentView(R.layout.activity_main);
tv= (TextView) findViewById(R.id.tv1);
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(POLLING_FREQ);
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_FREQ);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();


        if (mGoogleApiClient != null) {
            mGoogleApiClient.connect();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mGoogleApiClient != null) {
            mGoogleApiClient.connect();
        }
    }

    @Override
    protected void onPause() {d
        super.onPause();

        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }


        tv.setText(location + "");
        // Determine whether new location is better than current best
        // estimate
        if (null == mBestReading || location.getAccuracy() < mBestReading.getAccuracy()) {
            mBestReading = location;


            if (mBestReading.getAccuracy() < MIN_ACCURACY) {
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            }
        }
    }

    @Override
    public void onConnected(Bundle dataBundle) {
        // Get first reading. Get additional location updates if necessary
        if (servicesAvailable()) {

            // Get best last location measurement meeting criteria
            mBestReading = bestLastKnownLocation(MIN_LAST_READ_ACCURACY, FIVE_MIN);

            if (null == mBestReading
                    || mBestReading.getAccuracy() > MIN_LAST_READ_ACCURACY
                    || mBestReading.getTime() < System.currentTimeMillis() - TWO_MIN) {

                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);

               //Schedule a runnable to unregister location listeners

                    @Override
                    public void run() {
                        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, MainActivity.this);

                    }

                }, ONE_MIN, TimeUnit.MILLISECONDS);

            }

        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }


    private Location bestLastKnownLocation(float minAccuracy, long minTime) {
        Location bestResult = null;
        float bestAccuracy = Float.MAX_VALUE;
        long bestTime = Long.MIN_VALUE;

        // Get the best most recent location currently available
        Location mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        //tv.setText(mCurrentLocation+"");
        if (mCurrentLocation != null) {
            float accuracy = mCurrentLocation.getAccuracy();
            long time = mCurrentLocation.getTime();

            if (accuracy < bestAccuracy) {
                bestResult = mCurrentLocation;
                bestAccuracy = accuracy;
                bestTime = time;
            }
        }

        // Return best reading or null
        if (bestAccuracy > minAccuracy || bestTime < minTime) {
            return null;
        }
        else {
            return bestResult;
        }
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

    private boolean servicesAvailable() {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

        if (ConnectionResult.SUCCESS == resultCode) {
            return true;
        }
        else {
            GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0).show();
            return false;
        }
    }
}

2

मैंने Google द्वारा सुझाए गए नवीनतम लोकेशन पुलिंग विधियों (FusedLocationProviderClient का उपयोग करने के लिए) का उपयोग करके एक अपडेटेड (पिछले वर्ष) उत्तर के लिए इंटरनेट को स्कैन किया। मैं अंत में इस पर उतरा:

https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates

मैंने एक नया प्रोजेक्ट बनाया और इस अधिकांश कोड में कॉपी किया। बूम। यह काम करता हैं। और मुझे लगता है कि किसी भी पदावनत लाइनों के बिना।

इसके अलावा, सिम्युलेटर को एक जीपीएस स्थान प्राप्त नहीं होता है, जिसे मैं जानता हूं। इसे लॉग में रिपोर्ट करने के रूप में यह मिला: "सभी स्थान सेटिंग्स संतुष्ट हैं।"

और अंत में, यदि आप जानना चाहते थे (मैंने किया था), तो आपको Google डेवलपर कंसोल से Google मैप्स एपी कुंजी की आवश्यकता नहीं है, यदि आप चाहते हैं कि सभी जीपीएस स्थान है।

इसके अलावा उपयोगी उनके ट्यूटोरियल है। लेकिन मैं एक पूर्ण पृष्ठ ट्यूटोरियल / कोड उदाहरण, और वह चाहता था। उनका ट्यूटोरियल स्टैक करता है, लेकिन जब आप इसके लिए नए होते हैं तो भ्रमित होते हैं क्योंकि आपको नहीं पता होता है कि आपको पहले पृष्ठों से क्या टुकड़े चाहिए।

https://developer.android.com/training/location/index.html

और अंत में, इस तरह से चीजों को याद रखें:

मुझे न केवल mainActivity.Java को संशोधित करना पड़ा। मुझे स्ट्रिंग्स.xml, androidmanifest.xml, और सही build.gradle को भी संशोधित करना पड़ा। और आपकी गतिविधि_मैं.एक्सएमएल (लेकिन वह हिस्सा मेरे लिए आसान था)।

मुझे इस तरह की निर्भरताएं जोड़ने की आवश्यकता थी: कार्यान्वयन 'com.google.android.gms: play-services-location: 11.8.0', और Google Play सेवाओं को शामिल करने के लिए अपने Android स्टूडियो SDK की सेटिंग अपडेट करें। (फ़ाइल सेटिंग्स उपस्थिति प्रणाली सेटिंग्स Android एसडीके एसडीके उपकरण गूगल प्ले सेवाओं की जाँच करें)।

अद्यतन: एंड्रॉइड सिम्युलेटर को एक स्थान और स्थान परिवर्तन की घटनाओं को प्राप्त करने के लिए प्रतीत हुआ (जब मैंने सिम की सेटिंग्स में मूल्य बदल दिया)। लेकिन मेरा सबसे अच्छा और पहला परिणाम एक वास्तविक डिवाइस पर था। इसलिए वास्तविक उपकरणों पर परीक्षण करना शायद सबसे आसान है।


1

हाल ही में कोड के स्थान को प्राप्त करने के लिए, कुछ अच्छे विचारों को जानने के लिए, और अंत में एक अपेक्षाकृत सही पुस्तकालय और डेमो हासिल किया।

@ ग्रिफियस का जवाब अच्छा है

    //request all valid provider(network/gps)
private boolean requestAllProviderUpdates() {
    checkRuntimeEnvironment();
    checkPermission();

    if (isRequesting) {
        EasyLog.d("Request location update is busy");
        return false;
    }


    long minTime = getCheckTimeInterval();
    float minDistance = getCheckMinDistance();

    if (mMapLocationListeners == null) {
        mMapLocationListeners = new HashMap<>();
    }

    mValidProviders = getValidProviders();
    if (mValidProviders == null || mValidProviders.isEmpty()) {
        throw new IllegalArgumentException("Not available provider.");
    }

    for (String provider : mValidProviders) {
        LocationListener locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                if (location == null) {
                    EasyLog.e("LocationListener callback location is null.");
                    return;
                }
                printf(location);
                mLastProviderTimestamp = location.getTime();

                if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
                    finishResult(location);
                } else {
                    doLocationResult(location);
                }

                removeProvider(location.getProvider());
                if (isEmptyValidProviders()) {
                    requestTimeoutMsgInit();
                    removeUpdates();
                }
            }

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

            @Override
            public void onProviderEnabled(String provider) {
            }

            @Override
            public void onProviderDisabled(String provider) {
            }
        };
        getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener);
        mMapLocationListeners.put(provider, locationListener);
        EasyLog.d("Location request %s provider update.", provider);
    }
    isRequesting = true;
    return true;
}

//remove request update
public void removeUpdates() {
    checkRuntimeEnvironment();

    LocationManager locationManager = getLocationManager();
    if (mMapLocationListeners != null) {
        Set<String> keys = mMapLocationListeners.keySet();
        for (String key : keys) {
            LocationListener locationListener = mMapLocationListeners.get(key);
            if (locationListener != null) {
                locationManager.removeUpdates(locationListener);
                EasyLog.d("Remove location update, provider is " + key);
            }
        }
        mMapLocationListeners.clear();
        isRequesting = false;
    }
}

//Compared with the last successful position, to determine whether you need to filter
private boolean isNeedFilter(Location location) {
    checkLocation(location);

    if (mLastLocation != null) {
        float distance = location.distanceTo(mLastLocation);
        if (distance < getCheckMinDistance()) {
            return true;
        }
        if (location.getAccuracy() >= mLastLocation.getAccuracy()
                && distance < location.getAccuracy()) {
            return true;
        }
        if (location.getTime() <= mLastProviderTimestamp) {
            return true;
        }
    }
    return false;
}

private void doLocationResult(Location location) {
    checkLocation(location);

    if (isNeedFilter(location)) {
        EasyLog.d("location need to filtered out, timestamp is " + location.getTime());
        finishResult(mLastLocation);
    } else {
        finishResult(location);
    }
}

//Return to the finished position
private void finishResult(Location location) {
    checkLocation(location);

    double latitude = location.getLatitude();
    double longitude = location.getLongitude();
    float accuracy = location.getAccuracy();
    long time = location.getTime();
    String provider = location.getProvider();

    if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty()) {
        String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s";
        EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider));

        mLastLocation = location;
        synchronized (this) {
            Iterator<LocationResultListener> iterator =  mLocationResultListeners.iterator();
            while (iterator.hasNext()) {
                LocationResultListener listener = iterator.next();
                if (listener != null) {
                    listener.onResult(location);
                }
                iterator.remove();
            }
        }
    }
}

पूर्ण कार्यान्वयन: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

1. धन्यवाद @Gryphius समाधान विचारों, मैं भी पूरा कोड साझा करें।

2. प्रत्येक स्थान को पूरा करने के लिए अनुरोध, यह हटाने के लिए सबसे अच्छा है, अन्यथा फोन की स्थिति पट्टी हमेशा स्थिति आइकन प्रदर्शित करेगा


0

अपने अनुभव में, मैंने जीपीएस फिक्स के साथ जाना सबसे अच्छा पाया है जब तक कि यह उपलब्ध न हो। मुझे अन्य स्थान प्रदाताओं के बारे में ज्यादा जानकारी नहीं है, लेकिन मुझे पता है कि जीपीएस के लिए कुछ ट्रिक्स हैं, जिनका उपयोग थोड़ा घेटो सटीक माप देने के लिए किया जा सकता है। ऊंचाई अक्सर एक संकेत है, इसलिए आप हास्यास्पद मूल्यों की जांच कर सकते हैं। एंड्रॉइड लोकेशन फिक्स पर सटीकता माप है। यदि आप उपग्रहों की संख्या देख सकते हैं, तो यह भी सटीक संकेत दे सकता है।

सटीकता का एक बेहतर विचार प्राप्त करने का एक दिलचस्प तरीका बहुत तेज़ी से फ़िक्स के एक सेट के लिए पूछना हो सकता है, जैसे 10 सेकंड के लिए ~ 1 / सेकंड और फिर एक या दो मिनट के लिए सोएं। एक बात जो मैंने कही है वह यह मानकर चल रही है कि कुछ एंड्रॉइड डिवाइस वैसे भी ऐसा करेंगे। फिर आप आउटलेयर का खरपतवार निकालेंगे (मैंने यहां उल्लेख किया गया कलमन फ़िल्टर सुना है) और एक सिंगल फिक्स प्राप्त करने के लिए किसी प्रकार की केंद्रित रणनीति का उपयोग करें।

जाहिर है कि आपको यहां मिलने वाली गहराई इस बात पर निर्भर करती है कि आपकी आवश्यकताएं कितनी कठिन हैं। यदि आपको सर्वश्रेष्ठ स्थान प्राप्त करने की विशेष रूप से सख्त आवश्यकता है, तो मुझे लगता है कि आप पाएंगे कि जीपीएस और नेटवर्क स्थान सेब और संतरे के समान हैं। इसके अलावा जीपीएस डिवाइस से डिवाइस के लिए बेतहाशा अलग हो सकता है।


खैर, यह महत्वपूर्ण नहीं है कि यह सबसे अच्छा है, बस इतना है कि यह एक नक्शे पर साजिश करने के लिए पर्याप्त है और यह कि मैं बैटरी को खत्म नहीं करता हूं क्योंकि यह एक पृष्ठभूमि कार्य है।
निकल्स ए।

-3

Skyhook (http://www.skyhookwireless.com/) के पास एक स्थान प्रदाता है जो कि Google द्वारा प्रदान किए जाने वाले मानक की तुलना में बहुत तेज़ है। यह वही हो सकता है जो आप खोज रहे हैं। मैं उनके साथ संबद्ध नहीं हूं।


वास्तव में दिलचस्प है, वे केवल वाईफाई का उपयोग करते हैं, जो बहुत अच्छा है, लेकिन मुझे अभी भी काम करने की आवश्यकता है जब कोई वाईफाई या 3 जी / 2 जी कनेक्शन नहीं है, तो यह अमूर्तता की एक और परत जोड़ देगा। हालांकि अच्छा कैच।
निकॉल्स ए।

1
Skyhook वाईफाई, जीपीएस और सेल टावरों के संयोजन का उपयोग करता प्रतीत होता है। देखें skyhookwireless.com/howitworks तकनीकी जानकारी के लिए। वे हाल ही में कई डिजाइन जीत हासिल कर चुके हैं, उदाहरण के लिए मैक्वेस्ट, ट्वाइड्रॉइड, शॉपसेवी और सोनी एनजीपी। ध्यान दें कि उनके एसडीके को डाउनलोड करने और आज़माने के लिए स्वतंत्र प्रतीत होता है, लेकिन आपको अपने ऐप में इसे वितरित करने के लिए लाइसेंस के बारे में उनसे संपर्क करना होगा। दुर्भाग्य से वे अपनी वेब साइट पर कीमत सूचीबद्ध नहीं करते हैं।
एड बर्नेट

ओह मैं समझा। खैर, अगर यह व्यावसायिक रूप से उपयोग करने के लिए स्वतंत्र नहीं है, तो मुझे डर है कि मैं इसका उपयोग नहीं कर सकता।
निकल्स ए।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.