Cách tốt để có được vị trí của người dùng trong Android


211

Vấn đề:

Nhận vị trí hiện tại của người dùng trong ngưỡng ASAP và đồng thời tiết kiệm pin.

Tại sao vấn đề là một vấn đề:

Trước hết, android có hai nhà cung cấp; mạng và GPS. Đôi khi mạng tốt hơn và đôi khi GPS tốt hơn.

"Tốt hơn" tôi có nghĩa là tốc độ so với tỷ lệ chính xác.
Tôi sẵn sàng hy sinh độ chính xác vài mét nếu tôi có thể có được vị trí gần như ngay lập tức và không cần bật GPS.

Thứ hai, nếu bạn yêu cầu cập nhật thay đổi vị trí, không có gì được gửi nếu vị trí hiện tại ổn định.

Google có một ví dụ về việc xác định vị trí "tốt nhất" tại đây: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Nhưng tôi nghĩ rằng không có nơi nào tốt như nó nên /có thể là.

Tôi hơi bối rối tại sao google không có API được chuẩn hóa cho vị trí, nhà phát triển không cần phải quan tâm vị trí đó đến từ đâu, bạn chỉ nên chỉ định những gì bạn muốn và điện thoại sẽ chọn cho bạn.

Những gì tôi cần giúp đỡ với:

Tôi cần tìm một cách tốt để xác định vị trí "tốt nhất", có thể là một số heuristic hoặc có thể thông qua một số thư viện của bên thứ 3.

Điều này không có nghĩa là xác định nhà cung cấp tốt nhất!
Tôi có thể sẽ sử dụng tất cả các nhà cung cấp và chọn những người giỏi nhất trong số họ.

Bối cảnh của ứng dụng:

Ứng dụng sẽ thu thập vị trí của người dùng theo một khoảng thời gian cố định (giả sử cứ sau 10 phút hoặc lâu hơn) và gửi nó đến một máy chủ.
Ứng dụng nên tiết kiệm pin càng nhiều càng tốt và vị trí phải có độ chính xác X (50 - 100?).

Mục tiêu là sau này có thể vẽ đường đi của người dùng trong ngày trên bản đồ để tôi cần đủ độ chính xác cho điều đó.

Linh tinh

Bạn nghĩ gì về giá trị hợp lý trên độ chính xác mong muốn và được chấp nhận?
Tôi đã sử dụng 100m như được chấp nhận và 30m như mong muốn, đây có phải là điều đáng để hỏi không?
Tôi muốn có thể vẽ đường dẫn của người dùng trên bản đồ sau này.
Là 100m cho mong muốn và 500m cho chấp nhận tốt hơn?

Ngoài ra, ngay bây giờ tôi bật GPS tối đa 60 giây cho mỗi lần cập nhật vị trí, điều này có quá ngắn để có được vị trí nếu bạn ở trong nhà với độ chính xác có thể là 200m không?


Đây là mã hiện tại của tôi, mọi phản hồi đều được đánh giá cao (ngoài việc thiếu kiểm tra lỗi là 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
Đi lang thang rất muộn, nhưng "Nhà cung cấp vị trí hợp nhất" vừa được công bố tại IO 2013 có vẻ như nó đáp ứng nhiều nhu cầu của bạn - developer.android.com/google/play-service/location.html
Matt

không nên dòng cuối cùng của getBestLocation () là: return currentBestLocation; thay vì trả lại vị trí tốt nhất ;?
Gavriel

Câu trả lời:


164

Có vẻ như chúng tôi đang mã hóa cùng một ứng dụng ;-)
Đây là cách triển khai hiện tại của tôi. Tôi vẫn đang trong giai đoạn thử nghiệm beta của ứng dụng tải lên GPS của mình, vì vậy có thể có nhiều cải tiến có thể. nhưng nó có vẻ hoạt động khá tốt cho đến nay.

/**
 * 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;
}

Chỉnh sửa: đây là phần yêu cầu cập nhật định kỳ từ các nhà cung cấp vị trí:

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
}

Những điều cần cân nhắc:

  • không yêu cầu cập nhật GPS quá thường xuyên, nó sẽ làm cạn kiệt pin. Tôi hiện đang sử dụng 30 phút làm mặc định cho ứng dụng của mình.

  • thêm một 'khoảng cách tối thiểu để kiểm tra vị trí được biết đến cuối cùng'. không có điều này, các điểm của bạn sẽ "nhảy lung tung" khi GPS không khả dụng và vị trí đang được tam giác hóa từ các tháp di động. hoặc bạn có thể kiểm tra xem vị trí mới có nằm ngoài giá trị chính xác từ vị trí đã biết cuối cùng không.


2
Bạn không bao giờ thực sự có được một vị trí mới, bạn chỉ sử dụng các vị trí xảy ra ở đó từ các bản cập nhật trước đó. Tôi nghĩ rằng mã này sẽ có lợi rất nhiều bằng cách thực sự thêm một người nghe cập nhật vị trí bằng cách thỉnh thoảng bật GPS.
Nicklas A.

2
xin lỗi, tôi nghĩ rằng bạn chỉ quan tâm đến phần chọn tốt nhất từ ​​tất cả các địa điểm có sẵn. Tôi đã thêm mã ở trên yêu cầu những điều này là tốt. nếu một vị trí gps mới được nhận, nó sẽ được lưu trữ / tải lên ngay lập tức. nếu tôi nhận được cập nhật vị trí mạng, tôi sẽ lưu trữ để tham khảo và 'hy vọng' rằng tôi cũng sẽ nhận được cập nhật gps cho đến khi kiểm tra vị trí tiếp theo xảy ra.
Gryphius

2
Tôi cũng đã có một phương thức stopRecext () đã hủy bộ đếm thời gian. Cuối cùng tôi đã chuyển từ bộ đếm thời gian sang Bộ lập lịchThreadPoolExecutor, vì vậy, giờ đây, về cơ bản gọi hàm execor.shutdown () và hủy đăng ký tất cả các trình lắng nghe cập nhật vị trí
Gryphius

1
theo scm của tôi, stopRecext chỉ được gọi là gpsTimer.celon () và đặt gps_recorder_rucky = false, vì vậy, giống như trong trường hợp của bạn, sau đó không có người dọn dẹp. mã hiện tại theo dõi tất cả những người nghe đang hoạt động trong một vectơ, tôi đã không có điều này khi tôi viết câu trả lời này 1,5 năm trước.
Gryphius

1
nó đã có trên github , nhưng tôi không chắc đây vẫn là cách tốt nhất để làm công cụ GPS hiện nay. Afaik họ đã thực hiện nhiều cải tiến cho API vị trí kể từ khi tôi viết mã này.
Gryphius

33

Để chọn đúng nhà cung cấp vị trí cho ứng dụng của bạn, bạn có thể sử dụng các đối tượng Tiêu chí :

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

Đọc tài liệu cho requestLocationUpdates để biết thêm chi tiết về cách các đối số được đưa vào tài khoản:

Tần suất thông báo có thể được kiểm soát bằng các tham số minTime và minDistance. Nếu minTime lớn hơn 0, Trình quản lý vị trí có thể có khả năng nghỉ trong một phần nghìn giây giữa các lần cập nhật vị trí để tiết kiệm năng lượng. Nếu minDistance lớn hơn 0, một vị trí sẽ chỉ được phát nếu thiết bị di chuyển bằng mét minDistance. Để nhận thông báo thường xuyên nhất có thể, hãy đặt cả hai tham số thành 0.

Thêm suy nghĩ

  • Bạn có thể theo dõi độ chính xác của các đối tượng Location bằng Location.getAccuracy () , trả về độ chính xác ước tính của vị trí tính bằng mét.
  • các Criteria.ACCURACY_HIGHtiêu chí sẽ cho bạn lỗi dưới đây 100m, mà không phải là tốt như GPS có thể được, nhưng phù hợp với nhu cầu của bạn.
  • Bạn cũng cần theo dõi trạng thái của nhà cung cấp vị trí của mình và chuyển sang nhà cung cấp khác nếu người dùng không có mặt hoặc bị vô hiệu hóa.
  • Nhà cung cấp thụ động cũng có thể phù hợp với loại ứng dụng này: ý tưởng là sử dụng các cập nhật vị trí bất cứ khi nào chúng được yêu cầu bởi một ứng dụng khác và phát sóng toàn hệ thống.

Tôi đã xem xét Criterianhưng nếu vị trí mạng mới nhất là tuyệt vời (có thể biết qua wifi) và không mất thời gian hay pin để có được nó (getLastKnown), thì các tiêu chí có thể sẽ bỏ qua điều đó và thay vào đó trả lại GPS. Tôi không thể tin rằng google đã gây khó khăn cho các nhà phát triển.
Nicklas A.

Ngoài việc sử dụng Tiêu chí, bạn có thể, tại mỗi bản cập nhật vị trí được gửi bởi nhà cung cấp mà bạn đã chọn, hãy kiểm tra LastKnowLocation cho nhà cung cấp GPS và so sánh nó (độ chính xác và ngày) với vị trí hiện tại của bạn. Nhưng điều này đối với tôi có vẻ tốt hơn là yêu cầu từ thông số kỹ thuật của bạn; nếu đôi khi độ chính xác tốt hơn đôi khi đạt được, nó có thực sự hữu ích cho người dùng của bạn không?
Stéphane

Đó là những gì tôi đang làm bây giờ, vấn đề là tôi có một thời gian khó khăn để tìm hiểu nếu biết cuối cùng là đủ tốt. Tôi cũng có thể thêm rằng tôi không phải giới hạn bản thân trong một nhà cung cấp, tôi càng sử dụng nhanh thì tôi càng có thể nhận được khóa.
Nicklas A.

Hãy nhớ rằng PASSIVE_PROVIDER yêu cầu API cấp 8 trở lên.
Eduardo

@ Stéphane xin lỗi vì đã chỉnh sửa. Đừng chăm sóc nó. Bài viết của bạn là chính xác. Tôi đã sửa lỗi đó. Lấy làm tiếc. Trân trọng.
Gaucho

10

Trả lời hai điểm đầu tiên :

  • GPS sẽ luôn cung cấp cho bạn một vị trí chính xác hơn, nếu nó được bật và nếu không có những bức tường dày xung quanh .

  • Nếu vị trí không thay đổi, thì bạn có thể gọi getLastKnownLocation (Chuỗi) và truy xuất vị trí ngay lập tức.

Sử dụng một phương pháp thay thế :

Bạn có thể thử lấy id ô đang sử dụng hoặc tất cả các ô lân cận

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

Sau đó, bạn có thể tham khảo vị trí ô thông qua một số cơ sở dữ liệu mở (ví dụ: http://www.location-api.com/ hoặc http://opencellid.org/ )


Chiến lược sẽ là đọc danh sách ID tháp khi đọc vị trí. Sau đó, trong truy vấn tiếp theo (10 phút trong ứng dụng của bạn), hãy đọc lại chúng. Nếu ít nhất một số tháp giống nhau, thì nó an toàn để sử dụng getLastKnownLocation(String). Nếu họ không, sau đó chờ đợi onLocationChanged(). Điều này tránh sự cần thiết của cơ sở dữ liệu bên thứ ba cho vị trí. Bạn cũng có thể thử phương pháp này .


Vâng, nhưng tôi có vấn đề xảy ra nếu LastKnownLocation thực sự tồi tệ. Tôi cần một cách tốt để quyết định tốt nhất của hai địa điểm.
Nicklas A.

Bạn có thể lưu trữ thông tin về tháp và kiểm tra xem những tòa tháp đó có thay đổi không. Nếu họ đã làm, sau đó chờ một vị trí mới, nếu không (hoặc nếu chỉ một số thay đổi), sau đó sử dụng lại. Bằng cách đó bạn tránh so sánh các vị trí tháp với cơ sở dữ liệu.
Aleadam

Sử dụng tháp có vẻ như là một quá mức lớn đối với tôi, ý tưởng tốt.
Nicklas A.

@Nicklas mã không có gì phức tạp hơn thế. Tuy nhiên, bạn sẽ cần android.Manifest-01 # ACCESS_COARSE_UPDATE.
Aleadam

Vâng, nhưng tôi vẫn cần sử dụng dịch vụ của bên thứ ba và tôi cũng cần một cách để quyết định khi nào người dùng thông tin tháp qua dữ liệu vị trí, điều này chỉ cần thêm một lớp phức tạp.
Nicklas A.

9

Đây là giải pháp của tôi hoạt động khá tốt:

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

Xin chào Nicklas tôi có cùng một sự cân bằng vì vậy tôi có thể liên lạc với bạn bằng mọi cách .. tôi sẽ cảm ơn đầy đủ cho bạn nếu bạn có thể giúp chúng tôi ..
School Boy

Bạn có thể gửi toàn bộ mã? Cảm ơn, thực sự đánh giá cao
Rodi

Đó là tất cả các mã. Tôi không có quyền truy cập vào dự án nữa.
Nicklas A.

1
Có vẻ như bạn đã lấy mã của dự án này là "android-protips-location" và nó vẫn còn sống. Mọi người có thể thấy nó hoạt động như thế nào ở đây code.google.com/p/android-protips-location/source/browse/trunk/
ám

7

Độ chính xác của vị trí phụ thuộc chủ yếu vào nhà cung cấp vị trí được sử dụng:

  1. GPS - sẽ giúp bạn có độ chính xác vài mét (giả sử bạn có chức năng nhận GPS)
  2. Wifi - Sẽ giúp bạn có độ chính xác vài trăm mét
  3. Mạng di động - Sẽ giúp bạn có kết quả rất không chính xác (Tôi đã thấy độ lệch lên tới 4km ...)

Nếu đó là độ chính xác mà bạn đang tìm kiếm, thì GPS là lựa chọn duy nhất của bạn.

Tôi đã đọc một bài viết rất nhiều thông tin về nó ở đây .

Đối với thời gian chờ GPS - 60 giây là đủ, và trong hầu hết các trường hợp thậm chí là quá nhiều. Tôi nghĩ 30 giây là ổn và đôi khi còn chưa đến 5 giây ...

nếu bạn chỉ cần một địa điểm duy nhất, tôi đề nghị rằng trong onLocationChangedphương pháp của bạn , một khi bạn nhận được bản cập nhật, bạn sẽ hủy đăng ký người nghe và tránh sử dụng GPS không cần thiết.


Tôi không thực sự quan tâm từ nơi tôi có được vị trí của mình, tôi không muốn giới hạn tôi ở một nhà cung cấp
Nicklas A.

Bạn có thể đăng ký tất cả các nhà cung cấp vị trí có sẵn trên thiết bị (bạn có thể lấy danh sách tất cả các nhà cung cấp từ LocationManager.getProviders ()), nhưng nếu bạn đang tìm kiếm một bản sửa lỗi chính xác, trong hầu hết các trường hợp, nhà cung cấp mạng sẽ không hữu ích cho bạn.
Muzikant

Vâng, nhưng đây không phải là câu hỏi về lựa chọn giữa các nhà cung cấp, đây là câu hỏi về việc có được vị trí tốt nhất nói chung (ngay cả khi có nhiều nhà cung cấp tham gia)
Nicklas A.

4

Hiện tại tôi đang sử dụng vì điều này đáng tin cậy để lấy vị trí và tính khoảng cách cho ứng dụng của tôi ...... tôi đang sử dụng điều này cho ứng dụng taxi của mình.

sử dụng API tổng hợp mà nhà phát triển google đã phát triển với sự hợp nhất của Cảm biến GPS, Từ kế, Gia tốc kế cũng sử dụng Wifi hoặc vị trí ô để tính toán hoặc ước tính vị trí. Nó cũng có thể cung cấp cập nhật vị trí chính xác bên trong tòa nhà. để biết chi tiết, hãy liên kết https://developers.google.com/android/reference/com/google/android/gms/location/FuseLocationProviderApi

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

Tôi đã truy cập internet để tìm câu trả lời cập nhật (năm ngoái) bằng cách sử dụng các phương pháp kéo vị trí mới nhất được đề xuất bởi google (để sử dụng FuseLocationProviderClient). Cuối cùng tôi đã hạ cánh trên này:

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

Tôi đã tạo một dự án mới và sao chép trong hầu hết các mã này. Bùng nổ. Nó hoạt động. Và tôi nghĩ rằng không có bất kỳ dòng phản đối.

Ngoài ra, trình giả lập dường như không có được vị trí GPS mà tôi biết. Nó đã nhận được như báo cáo này trong nhật ký: "Tất cả các cài đặt vị trí được thỏa mãn."

Và cuối cùng, trong trường hợp bạn muốn biết (tôi đã làm), bạn KHÔNG cần khóa api google maps từ bảng điều khiển dành cho nhà phát triển google, nếu tất cả những gì bạn muốn là vị trí GPS.

Cũng hữu ích là hướng dẫn của họ. Nhưng tôi muốn có một ví dụ hướng dẫn / mã đầy đủ một trang, và đó. Các ngăn xếp hướng dẫn của họ nhưng khó hiểu khi bạn chưa quen với điều này bởi vì bạn không biết những gì bạn cần từ các trang trước đó.

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

Và cuối cùng, hãy nhớ những điều như thế này:

Tôi không chỉ phải sửa đổi mainActivity.Java. Tôi cũng đã phải sửa đổi String.xml, androidmanifest.xml và build.gradle chính xác. Và cả Activity_Main.xml của bạn (nhưng phần đó rất dễ đối với tôi).

Tôi cần thêm các phụ thuộc như thế này: triển khai 'com.google.android.gms: play-services-location: 11.8.0' và cập nhật cài đặt SDK Android studio của tôi để bao gồm các dịch vụ google play. (cài đặt tệp xuất hiện cài đặt hệ thống cài đặt Android SDK SDK Công cụ kiểm tra các dịch vụ google play).

cập nhật: trình giả lập Android dường như nhận được một sự kiện thay đổi vị trí và vị trí (khi tôi thay đổi giá trị trong cài đặt của sim). Nhưng kết quả tốt nhất và đầu tiên của tôi là trên một thiết bị thực tế. Vì vậy, nó có thể dễ dàng nhất để kiểm tra trên các thiết bị thực tế.


1

Gần đây được tái cấu trúc để có được vị trí của mã, tìm hiểu một số ý tưởng hay và cuối cùng đã đạt được một thư viện và Demo tương đối hoàn hảo.

Câu trả lời của @ Gryphius là tốt

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

Hoàn thành triển khai: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

1.Cảm ơn ý tưởng giải pháp @Gryphius, tôi cũng chia sẻ mã hoàn chỉnh.

2.Mỗi yêu cầu hoàn thành vị trí, tốt nhất là xóaUpdates, nếu không, thanh trạng thái điện thoại sẽ luôn hiển thị biểu tượng định vị


0

Theo kinh nghiệm của tôi, tôi đã tìm thấy cách tốt nhất để khắc phục GPS trừ khi nó không khả dụng. Tôi không biết nhiều về các nhà cung cấp vị trí khác, nhưng tôi biết rằng đối với GPS, có một vài thủ thuật có thể được sử dụng để đưa ra một chút về độ chính xác ghetto. Độ cao thường là một dấu hiệu, vì vậy bạn có thể kiểm tra các giá trị vô lý. Có các biện pháp chính xác về sửa lỗi vị trí Android. Ngoài ra nếu bạn có thể thấy số lượng vệ tinh được sử dụng, điều này cũng có thể chỉ ra độ chính xác.

Một cách thú vị để có được ý tưởng tốt hơn về độ chính xác có thể là yêu cầu một bộ sửa chữa rất nhanh, như ~ 1 / giây trong 10 giây và sau đó ngủ trong một hoặc hai phút. Một cuộc nói chuyện mà tôi đã từng dẫn đến việc tin rằng một số thiết bị Android sẽ làm điều này bằng mọi cách. Sau đó, bạn sẽ loại bỏ các ngoại lệ (Tôi đã nghe bộ lọc Kalman được đề cập ở đây) và sử dụng một số loại chiến lược định tâm để có một bản sửa lỗi duy nhất.

Rõ ràng độ sâu bạn có được ở đây phụ thuộc vào mức độ khó của bạn. Nếu bạn có yêu cầu đặc biệt nghiêm ngặt để có được vị trí TỐT NHẤT có thể, tôi nghĩ bạn sẽ thấy rằng GPS và vị trí mạng tương tự như táo và cam. Ngoài ra GPS có thể rất khác nhau từ thiết bị này sang thiết bị khác.


Chà, điều quan trọng không phải là nó tốt nhất, chỉ là nó đủ tốt để vẽ trên bản đồ và tôi không làm cạn pin vì đây là nhiệm vụ nền.
Nicklas A.

-3

Skyhook (http: //www.skyhookwless.com/) có nhà cung cấp vị trí nhanh hơn nhiều so với tiêu chuẩn mà Google cung cấp. Nó có thể là những gì bạn đang tìm kiếm. Tôi không liên kết với họ.


Thật thú vị, họ dường như chỉ sử dụng WiFi, tuy nhiên nó rất đẹp nhưng tôi vẫn cần nó để hoạt động khi không có kết nối wifi hoặc 3G / 2G vì vậy điều này sẽ thêm một lớp trừu tượng khác. Bắt tốt mặc dù.
Nicklas A.

1
Skyhook dường như sử dụng kết hợp WiFi, GPS và tháp di động. Xem skyhookwpered.com/howitworks để biết chi tiết kỹ thuật. Họ đã nhận được một số chiến thắng thiết kế gần đây, ví dụ như Mapquest, Twydroid, ShopSavvy và Sony NGP. Lưu ý rằng việc tải xuống và dùng thử SDK của họ dường như là miễn phí nhưng bạn phải liên hệ với họ về giấy phép phân phối nó trong ứng dụng của bạn. Thật không may, họ không liệt kê giá trên trang web của họ.
Ed Burnette

Ồ, tôi hiểu rồi. Chà, nếu nó không được sử dụng thương mại thì tôi sợ rằng tôi không thể sử dụng nó.
Nicklas A.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.