ฉันจะตรวจสอบสถานะปัจจุบันของเครื่องรับ GPS ได้อย่างไร?


90

ฉันจะตรวจสอบสถานะปัจจุบันของเครื่องรับ GPS ได้อย่างไร? ฉันตรวจสอบLocationListener onStatusChangedวิธีการแล้ว แต่ดูเหมือนว่าจะไม่ได้ผลหรือมีความเป็นไปได้ที่ไม่ถูกต้อง

โดยทั่วไปฉันต้องทราบว่าไอคอน GPS ที่ด้านบนของหน้าจอกะพริบ (ไม่มีการแก้ไขจริง) หรือค้าง (มีการแก้ไข)

คำตอบ:


150

ในฐานะผู้พัฒนา SpeedView: เครื่องวัดความเร็ว GPS สำหรับ Android ฉันต้องลองวิธีแก้ปัญหานี้ทุกวิถีทางโดยให้ผลลัพธ์เชิงลบเหมือนกัน ขอย้ำสิ่งที่ไม่ได้ผล:

  1. onStatusChanged () ไม่ได้รับการเรียกจาก Eclair และ Froyo
  2. แน่นอนว่าการนับดาวเทียมที่มีอยู่ทั้งหมดก็ไร้ประโยชน์
  3. การตรวจสอบว่าดาวเทียมใดคืนค่าจริงสำหรับ usedInFix () ก็ไม่เป็นประโยชน์เช่นกัน ระบบสูญเสียการแก้ไขอย่างชัดเจน แต่ยังคงรายงานว่ายังมี sats หลายตัวที่ใช้อยู่

นี่เป็นวิธีแก้ปัญหาเดียวที่ฉันพบและเป็นโซลูชันที่ฉันใช้จริงในแอป สมมติว่าเรามีคลาสง่ายๆนี้ที่ใช้ GpsStatus.Listener:

private class MyGPSListener implements GpsStatus.Listener {
    public void onGpsStatusChanged(int event) {
        switch (event) {
            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                if (mLastLocation != null)
                    isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

                if (isGPSFix) { // A fix has been acquired.
                    // Do something.
                } else { // The fix has been lost.
                    // Do something.
                }

                break;
            case GpsStatus.GPS_EVENT_FIRST_FIX:
                // Do something.
                isGPSFix = true;

                break;
        }
    }
}

ตกลงตอนนี้ใน onLocationChanged () เราเพิ่มสิ่งต่อไปนี้:

@Override
public void onLocationChanged(Location location) {
    if (location == null) return;

    mLastLocationMillis = SystemClock.elapsedRealtime();

    // Do something.

    mLastLocation = location;
}

และนั่นแหล่ะ โดยทั่วไปนี่คือบรรทัดที่ทำทุกอย่าง:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

แน่นอนคุณสามารถปรับค่ามิลลิวินาทีได้ แต่ฉันขอแนะนำให้ตั้งค่าประมาณ 3-5 วินาที

สิ่งนี้ใช้งานได้จริงและแม้ว่าฉันจะไม่ได้ดูซอร์สโค้ดที่วาดไอคอน GPS ดั้งเดิม แต่สิ่งนี้ก็ใกล้เคียงกับการจำลองพฤติกรรมของมัน หวังว่านี่จะช่วยใครบางคนได้


สวัสดีฉันสงสัยว่าทำไมการนับดาวเทียมที่มีอยู่จึงไร้ประโยชน์เหมือนในตัวอย่างนี้? หากพบจำนวนดาวเทียมเป็น 0 หมายความว่าไม่มีการเชื่อมต่อหรือฉันคิดผิด? groups.google.com/group/android-developers/browse_thread/thread/…
per_jansson

3
สวัสดี Stephen คุณช่วยอธิบายได้ไหมว่าทำไม GPSFix ถึงใช้งานได้ ขอบคุณ Nick
nickfox

อย่างไรก็ตามฉันสังเกตเห็นว่าใน ICS พวกเขาเพิ่มเวลาจนกว่าระบบจะเริ่มรายงานว่าการแก้ไข GPS หายไป อย่างน้อยใน 4.0.3 ก็แม่นยำ 10 วินาที
soundmaven

ใช้งานได้ดีและใช้เวลา 10 วินาทีเมื่อเทียบกับ 3-5 สำหรับ ICS ก็ใช้ได้ดีเช่นกัน โชคดีที่การแก้ไขไม่ใช่คุณสมบัติที่จำเป็นของแอปของฉัน แต่เป็นการดีที่จะรู้ ขอบคุณ.
ทอม

1
แต่สิ่งนี้ไม่หยุดเมื่อmLastLocationMillisถูกตั้งค่าโดยแหล่งอื่นที่ไม่ใช่ GPS หรือไม่? ระบบจะอ้างว่าisGPSFixเป็นความจริงมากกว่า แต่ในความเป็นจริงมันเป็นเพียงการแก้ไขใด ๆ (อาจเป็นหนึ่งในเครือข่ายโทรศัพท์)
ถล่ม

25

ไอคอน GPS ดูเหมือนจะเปลี่ยนสถานะตามเจตนาการออกอากาศที่ได้รับ คุณสามารถเปลี่ยนสถานะได้ด้วยตัวเองด้วยตัวอย่างโค้ดต่อไปนี้:

แจ้งว่าเปิดใช้งาน GPS แล้ว:

Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

แจ้งว่า GPS กำลังได้รับการแก้ไข:

Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

แจ้งว่า GPS ไม่ได้รับการแก้ไขอีกต่อไป:

Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

แจ้งว่า GPS ถูกปิดใช้งาน:

Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

ตัวอย่างรหัสในการลงทะเบียนผู้รับไปยังเจตนา:

// MyReceiver must extend BroadcastReceiver
MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter("android.location.GPS_ENABLED_CHANGE");
filter.addAction("android.location.GPS_FIX_CHANGE");
registerReceiver(receiver, filter);

เมื่อได้รับความตั้งใจในการออกอากาศเหล่านี้คุณจะสังเกตเห็นการเปลี่ยนแปลงของสถานะ GPS อย่างไรก็ตามคุณจะได้รับแจ้งก็ต่อเมื่อสถานะเปลี่ยนไป ดังนั้นจึงไม่สามารถระบุสถานะปัจจุบันโดยใช้เจตนาเหล่านี้ได้


ฉันไม่รู้ว่าคุณสามารถส่งการออกอากาศนั้นจากแอปพลิเคชันของคุณได้อย่างไรเพราะดูเหมือนว่าเป็นการออกอากาศที่มีการป้องกันระบบซึ่งหมายความว่ามีเพียงระบบเท่านั้นที่สามารถส่งได้ แอปใดก็ตามที่ส่งเจตนานั้นควรขัดข้อง
JoxTraex

เป็นไปได้ที่จะส่งไปเมื่อหกปีก่อนตอนที่ฉันเขียนคำตอบ เห็นได้ชัดว่าพวกเขาได้เพิ่มการป้องกันบางอย่างให้กับระบบตั้งแต่นั้นมา
sast

ฉันใช้ความตั้งใจเหล่านี้เพื่อบอกเวลาที่แอปอื่น ๆ ใช้ GPS ฉันเชื่อว่าเริ่มต้นด้วย Nougat คุณไม่สามารถแม้แต่จะฟังเจตนาเหล่านี้ได้อีกต่อไปหรือว่ามันเปลี่ยนไปแล้ว! ฉันไม่ต้องการฟังตำแหน่งด้วยแอปของฉันเอง ใครมีไอเดียอื่น ๆ
Flyview

ใช่ฉันมีข้อผิดพลาดนั้น: 05-14 10: 25: 24.113 17344-17344 / xxx.yyy.zzz.debug E / AndroidRuntime: FATAL EXCEPTION: main Process: xxx.yyy.zzz.debug, PID: 17344 java lang.SecurityException: Permission Denial: not allowed to send broadcast android.location.GPS_FIX_CHANGE from pid = 17344, uid = 10416
unlimited101

19

สมาชิกใหม่น่าเสียดายที่ฉันไม่สามารถแสดงความคิดเห็นหรือลงคะแนนได้อย่างไรก็ตามโพสต์ของ Stephen Daye ด้านบนเป็นวิธีแก้ปัญหาที่สมบูรณ์แบบสำหรับปัญหาเดียวกันกับที่ฉันต้องการความช่วยเหลือ

การเปลี่ยนแปลงเล็กน้อยในบรรทัดต่อไปนี้:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

ถึง:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);

โดยพื้นฐานแล้วเมื่อฉันสร้างเกมที่มีการเคลื่อนไหวช้าและช่วงเวลาการอัปเดตของฉันถูกตั้งไว้ที่ 5 วินาทีแล้วเมื่อสัญญาณ gps หมดเป็นเวลา 10+ วินาทีนั่นเป็นเวลาที่เหมาะสมในการเรียกใช้บางสิ่ง

ไชโยเพื่อนใช้เวลาประมาณ 10 ชั่วโมงในการแก้ปัญหานี้ก่อนที่ฉันจะพบโพสต์ของคุณ :)


14

โอเคลองใช้คำตอบและการอัปเดตทั้งหมดรวมกันแล้วทำสิ่งนี้:

ตัวฟัง GPS อาจเป็นดังนี้:

GpsStatus.Listener listener = new GpsStatus.Listener() {
    void onGpsStatusChanged(int event) {
        if (event == GPS_EVENT_SATELLITE_STATUS) {
            GpsStatus status = mLocManager.getGpsStatus(null);
            Iterable<GpsSatellite> sats = status.getSatellites();
            // Check number of satellites in list to determine fix state
        }
    }
}

API ไม่ชัดเจนเล็กน้อยเกี่ยวกับเวลาและข้อมูล GPS และดาวเทียมที่ได้รับ แต่ฉันคิดว่าควรพิจารณาว่ามีดาวเทียมจำนวนเท่าใด หากต่ำกว่าสามคุณจะไม่สามารถแก้ไขได้ หากเป็นมากกว่านั้นคุณควรได้รับการแก้ไข

การลองผิดลองถูกน่าจะเป็นวิธีพิจารณาว่า Android รายงานข้อมูลดาวเทียมบ่อยเพียงใดและข้อมูลใดบ้างที่GpsSatelliteมีอยู่


ปัญหาในการนับดาวเทียมที่มีอยู่คือแม้ว่าคุณจะมีดาวเทียม 5 ดวงในมุมมอง แต่ก็ไม่ได้หมายความว่าจะมีการแก้ไขเสมอไป (คุณพูดถูกต้องโดยเขียนว่า "ถ้ามีมากกว่านี้คุณควรได้รับการแก้ไข")
ที่

แน่นอน. แม้ว่าฉันจะไม่ทราบข้อมูลเพิ่มเติมเกี่ยวกับข้อมูลที่ต้องใช้ในการแก้ไขหรือวิธี / ว่าสามารถดึงข้อมูลจากGpsSatelliteวัตถุได้อย่างไร
Christopher Orr

อีกความคิดหนึ่ง .. คุณไม่ได้พูดถึงสิ่งนี้ในคำถามของคุณ แต่คุณได้ลองใช้เพียงแค่LocationManager.requestLocationUpdatesตั้งค่าเวลาและระยะทางเป็น 0 หรือไม่? สิ่งนี้จะส่งการแก้ไข GPS ให้คุณทันทีที่เกิดขึ้น หากคุณไม่ได้รับอะไรเลยแสดงว่าคุณไม่ได้รับการแก้ไข คุณสามารถรวมสิ่งนี้กับตัวฟังสถานะด้านบนได้หากต้องการ
Christopher Orr

1
การทำซ้ำ "sats" และการตรวจสอบ usedInFix () ใน GpsSatellite อาจจะ?
DeliriumTremens

8

หลังจากทำงานกับ GPS บน windows mobile ได้ไม่กี่ปีฉันก็รู้ว่าแนวคิดเรื่อง "การสูญเสีย" การแก้ไข GPS อาจเป็นเรื่องส่วนตัว เพียงแค่ฟังสิ่งที่ GPS บอกคุณการเพิ่ม NMEAListener และการแยกวิเคราะห์ประโยคจะบอกคุณว่าการแก้ไขนั้น "ถูกต้อง" หรือไม่ ดูhttp://www.gpsinformation.org/dale/nmea.htm#GGA น่าเสียดายที่ GPS บางตัวค่านี้จะผันผวนไปมาแม้ในระหว่างการทำงานปกติในพื้นที่ "การแก้ไขที่ดี"

ดังนั้นวิธีแก้ปัญหาอื่น ๆ คือการเปรียบเทียบเวลา UTC ของตำแหน่ง GPS กับเวลาของโทรศัพท์ (แปลงเป็น UTC) หากเป็นช่วงเวลาที่แตกต่างกันคุณสามารถสันนิษฐานได้ว่าคุณทำตำแหน่ง GPS หาย


คุณช่วยอธิบายวิธีเปรียบเทียบเวลาได้ไหม ในคำตอบของ Stephen Daye เขาเปรียบเทียบความแตกต่างของเวลาระหว่างเวลาที่เกิดการแก้ไขครั้งสุดท้ายกับเหตุการณ์ GPS_EVENT_SATELLITE_STATUS ล่าสุด ... ไม่แน่ใจว่ากำลังวัดอะไร
Rokey Ge

7

พบปัญหาที่คล้ายกันในขณะที่ทำงานกับโครงการ MSc ของฉันดูเหมือนว่าคำตอบของ Daye จะรายงานผิดพลาดว่า "ไม่แก้ไข" ในขณะที่อุปกรณ์ยังคงอยู่ในตำแหน่งคงที่ ฉันได้แก้ไขโซลูชันเพียงเล็กน้อยซึ่งดูเหมือนว่าจะใช้ได้ดีสำหรับฉันในตำแหน่งที่คงที่ ฉันจะไม่ส่งผลกระทบต่อแบตเตอรี่อย่างไรเนื่องจากไม่ใช่ปัญหาหลักของฉัน แต่นี่คือวิธีที่ฉันทำได้โดยการขอการอัปเดตตำแหน่งอีกครั้งเมื่อการแก้ไขหมดเวลา

private class MyGPSListener implements GpsStatus.Listener {
    public void onGpsStatusChanged(int event) {
        switch (event) {
        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
            if (Global.getInstance().currentGPSLocation != null)
            {
                if((SystemClock.elapsedRealtime() - mLastLocationMillis) < 20000)
                {
                    if (!hasGPSFix) 
                        Log.i("GPS","Fix Acquired");
                    hasGPSFix = true;
                } 
                else
                {
                    if (hasGPSFix) 
                    {
                        Log.i("GPS","Fix Lost (expired)");
                        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener);
                    }
                    hasGPSFix = false;
                }
            }
            break;
        case GpsStatus.GPS_EVENT_FIRST_FIX:
            Log.i("GPS", "First Fix/ Refix");
            hasGPSFix = true;
            break;
        case GpsStatus.GPS_EVENT_STARTED:
            Log.i("GPS", "Started!");
            break;
        case GpsStatus.GPS_EVENT_STOPPED:
            Log.i("GPS", "Stopped");
            break;
        }
    }
}

5

การรวบรวมแนวทางการทำงานทุกอย่างเข้าด้วยกันจะทำให้เกิดสิ่งนี้ (เช่นกันกับการเลิกใช้งานGpsStatus.Listener):

private GnssStatus.Callback mGnssStatusCallback;
@Deprecated private GpsStatus.Listener mStatusListener;
private LocationManager mLocationManager;

@Override
public void onCreate() {
    mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

    mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    if (checkPermission()) {
       mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_INTERVAL, MIN_DISTANCE, this);
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mGnssStatusCallback = new GnssStatus.Callback() {
            @Override
            public void onSatelliteStatusChanged(GnssStatus status) {
                satelliteStatusChanged();
            }

            @Override
            public void onFirstFix(int ttffMillis) {
                gpsFixAcquired();

            }
        };
        mLocationManager.registerGnssStatusCallback(mGnssStatusCallback);
    } else {
        mStatusListener = new GpsStatus.Listener() {
            @Override
            public void onGpsStatusChanged(int event) {
                switch (event) {
                    case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                        satelliteStatusChanged();
                        break;
                    case GpsStatus.GPS_EVENT_FIRST_FIX:
                        // Do something.
                        gpsFixAcquired();
                        break;
                }
            }
        };
        mLocationManager.addGpsStatusListener(mStatusListener);
    }
}

private void gpsFixAcquired() {
    // Do something.
    isGPSFix = true;
}

private void satelliteStatusChanged() {
    if (mLastLocation != null)
        isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);

    if (isGPSFix) { // A fix has been acquired.
        // Do something.
    } else { // The fix has been lost.
        // Do something.
    }
}

@Override
public void onLocationChanged(Location location) {
    if (location == null) return;

    mLastLocationMillis = SystemClock.elapsedRealtime();

    mLastLocation = location;
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {

}

@Override
public void onProviderEnabled(String s) {

}

@Override
public void onProviderDisabled(String s) {

}

หมายเหตุ: คำตอบนี้เป็นการรวมกันของคำตอบข้างต้น


1
ตราบใดที่คุณให้เครดิตผู้แต่งคนอื่น ๆ ก็ไม่มีปัญหาในการรับ upvotes ของคุณเองสำหรับงานใหม่หรืองานลอกเลียนแบบ กฎที่นี่มีความกังวลมากขึ้นเกี่ยวกับผู้คนที่ลอกเลียนคำตอบของคนอื่นและนำไปใช้ที่อื่นใน Stack Overflow เพื่อดึงดูดคำตอบที่ไม่สุจริต เนื่องจากคุณได้กล่าวว่าคุณได้สร้างคำตอบอื่น ๆ แล้วฉันคิดว่านี่เป็นเรื่องปกติ
แขวน

3

หากคุณต้องการทราบว่ามีการแก้ไขหรือไม่ให้ตรวจสอบตำแหน่งที่ทราบล่าสุดที่เครื่องรับ GPS ให้มาและตรวจสอบค่า. getTime () เพื่อดูว่าอายุเท่าไหร่ หากล่าสุดเพียงพอ (เช่น ... ไม่กี่วินาที) คุณจะต้องแก้ไข

   LocationManager lm = (LocationManager)context.getSystemService(LOCATION_SERVICE); 
   Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

   // Get the time of the last fix
   long lastFixTimeMillis = loc.getTime(); 

... และสุดท้ายเปรียบเทียบกับวันที่เวลาปัจจุบัน (ใน UTC!) หากล่าสุดคุณสามารถแก้ไขได้

ฉันทำสิ่งนั้นในแอปของฉันและจนถึงตอนนี้ก็ดีมาก


+1 ดูเหมือนจะคุ้มค่าที่จะลองหากคุณต้องการทราบทันทีว่ามีการแก้ไขหรือไม่
AgentKnopf

2

คุณสามารถลองใช้LocationManager.addGpsStatusListenerเพื่อรับการอัปเดตเมื่อสถานะ GPS เปลี่ยนไป ดูเหมือนว่าGPS_EVENT_STARTEDและGPS_EVENT_STOPPEDอาจเป็นสิ่งที่คุณกำลังมองหา


3
ตัวรับฟังสถานะรวมกับGPS_EVENT_FIRST_FIXเสียงที่ใกล้เคียงกันมากขึ้น
Christopher Orr

2

ฉันอาจจะคิดผิด แต่ดูเหมือนว่าผู้คนจะออกนอกประเด็นไป

ฉันแค่ต้องรู้ว่าไอคอน gps ที่ด้านบนของหน้าจอกะพริบหรือไม่ (ไม่มีการแก้ไขจริง)

ที่ทำได้อย่างง่ายดายด้วย

LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);

หากต้องการดูว่าคุณมีการแก้ไขที่มั่นคงหรือไม่สิ่งต่างๆจะยุ่งยากกว่าเล็กน้อย:

public class whatever extends Activity {
    LocationManager lm;
    Location loc;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        
        lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        loc = null;
        request_updates();        
    }

    private void request_updates() {
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // GPS is enabled on device so lets add a loopback for this locationmanager
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, locationListener);
        }      
    }

    LocationListener locationListener = new LocationListener() {
        public void onLocationChanged(Location location) {
            // Each time the location is changed we assign loc
            loc = location;
        }

         // Need these even if they do nothing. Can't remember why.
         public void onProviderDisabled(String arg0) {}
         public void onProviderEnabled(String provider) {}
         public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

ตอนนี้เมื่อใดก็ตามที่คุณต้องการดูว่าคุณมีการแก้ไขหรือไม่?

if (loc != null){
    // Our location has changed at least once
    blah.....
}

หากคุณต้องการเป็นแฟนซีคุณสามารถหมดเวลาโดยใช้ System.currentTimeMillis () และ loc.getTime ()

ทำงานได้อย่างน่าเชื่อถืออย่างน้อยก็ใน N1 ตั้งแต่ 2.1


3
โซลูชันของคุณซับซ้อนเกินไปสำหรับสิ่งที่ทำ อย่างไรก็ตามมันทำได้น้อยมาก จะเกิดอะไรขึ้นถ้าหลังจาก gps แก้ไขตำแหน่งของฉันฉันไปที่สถานีใต้ดินทำให้ gps เสียการแก้ไข
meandre

1

ด้วย LocationManager คุณสามารถ getLastKnownLocation () หลังจากที่คุณ getBestProvider () สิ่งนี้ทำให้คุณมีวัตถุ Location ซึ่งมีเมธอด getAccuracy () เป็นเมตรและ getTime () ในหน่วย UTC มิลลิวินาที

ข้อมูลนี้ให้ข้อมูลเพียงพอหรือไม่

หรือบางทีคุณอาจทำซ้ำบน LocationProviders และดูว่าแต่ละคนตรงตามเกณฑ์ (ACCURACY_COARSE) หรือไม่


1

กระทู้เยอะมาก ...

GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
                        public void onGpsStatusChanged(int event) {
                            if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
                                showMessageDialog("GPS fixed");
                            }
                        }
                 };

เพิ่มรหัสนี้ด้วย addGpsListener ... showMessageDialog ... แสดงหน้าต่างโต้ตอบมาตรฐานพร้อมสตริง

ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน :) ขอบคุณมาก: =) (สำหรับโพสต์นี้ยังไม่สามารถโหวตได้)


นี่เป็นเพียงการแก้ไขครั้งแรก ถ้าคุณเข้าไปในอุโมงค์ล่ะ?
Leos Literak

1

หากคุณไม่ต้องการการอัปเดตในทันทีที่การแก้ไขหายไปคุณสามารถแก้ไขโซลูชันของ Stephen Daye ด้วยวิธีนั้นซึ่งคุณมีวิธีการตรวจสอบว่ายังมีการแก้ไขอยู่หรือไม่

ดังนั้นคุณสามารถตรวจสอบได้ทุกเมื่อที่คุณต้องการข้อมูล GPS และคุณไม่จำเป็นต้องใช้ GpsStatus.Listener

ตัวแปร "global" ได้แก่ :

private Location lastKnownLocation;
private long lastKnownLocationTimeMillis = 0;
private boolean isGpsFix = false;

นี่คือวิธีการที่เรียกว่าภายใน "onLocationChanged ()" เพื่อจดจำเวลาอัปเดตและตำแหน่งปัจจุบัน นอกจากนั้นยังอัปเดต "isGpsFix":

private void handlePositionResults(Location location) {
        if(location == null) return;

        lastKnownLocation = location;
        lastKnownLocationTimeMillis = SystemClock.elapsedRealtime();

        checkGpsFix(); // optional
    }

วิธีนี้เรียกว่าเมื่อใดก็ตามที่ฉันต้องการทราบว่ามีการแก้ไข GPS:

private boolean checkGpsFix(){

    if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) {
        isGpsFix = true;

    } else {
        isGpsFix = false;
        lastKnownLocation = null;
    }
    return isGpsFix;
}

ในการใช้งานของฉันฉันเรียกใช้ checkGpsFix () ก่อนและถ้าผลลัพธ์เป็นจริงฉันใช้ตัวแปร "lastKnownLocation" เป็นตำแหน่งปัจจุบันของฉัน


1

ฉันรู้ว่านี่มันสายไปหน่อย อย่างไรก็ตามทำไมไม่ใช้ NMEAListener ถ้าคุณต้องการทราบว่าคุณมีวิธีแก้ไขหรือไม่ จากสิ่งที่ฉันได้อ่าน NMEAListener จะให้ประโยค NMEA แก่คุณและจากนั้นคุณจะเลือกประโยคที่ถูกต้อง

ประโยค RMC มีสถานะการแก้ไขซึ่งเป็น A สำหรับ OK หรือ V สำหรับคำเตือน ประโยค GGA ประกอบด้วย Fix Quality (0 ไม่ถูกต้อง 1 GPS หรือ 2 DGPS)

ฉันไม่สามารถเสนอรหัส java ให้คุณได้เนื่องจากฉันเพิ่งเริ่มใช้ Android แต่ฉันได้ทำไลบรารี GPS ใน C # สำหรับแอป Windows ซึ่งฉันต้องการใช้กับ Xamarin ฉันเจอหัวข้อนี้เพราะฉันกำลังมองหาข้อมูลผู้ให้บริการ

จากสิ่งที่ฉันได้อ่านเกี่ยวกับวัตถุตำแหน่งฉันไม่ค่อยสบายใจเกี่ยวกับวิธีการเช่น getAccuracy () และ hasAccuracy () ฉันคุ้นเคยกับการแยกค่า HDOP และ VDOP ของประโยค NMEA เพื่อพิจารณาว่าการแก้ไขของฉันแม่นยำเพียงใด เป็นเรื่องปกติที่จะมีการแก้ไข แต่มี HDOP ที่มีหมัดซึ่งหมายความว่าความแม่นยำในแนวนอนของคุณไม่ดีเลย ตัวอย่างเช่นการนั่งที่โต๊ะทำงานของคุณโดยใช้อุปกรณ์ Bluetooth GPS ภายนอกอย่างหนักกับหน้าต่างคุณมีแนวโน้มที่จะได้รับการแก้ไข แต่ HDOP และ VDOP แย่มาก วางอุปกรณ์ GPS ของคุณในกระถางดอกไม้ด้านนอกหรือสิ่งที่คล้ายกันหรือเพิ่มเสาอากาศภายนอกลงใน GPS คุณจะได้รับค่า HDOP และ VDOP ที่ดีในทันที


0

อาจเป็นความเป็นไปได้ที่ดีที่สุดในการสร้าง TimerTask ที่ตั้งค่า Location ที่ได้รับเป็นค่าหนึ่ง (null?) อย่างสม่ำเสมอ หาก GPSListener ได้รับค่าใหม่เครื่องจะอัปเดตตำแหน่งด้วยข้อมูลปัจจุบัน

ฉันคิดว่านั่นจะเป็นทางออกที่ใช้ได้ผล


0

คุณบอกว่าคุณได้ลองใช้ onStatusChanged () แล้ว แต่มันได้ผลสำหรับฉัน

นี่คือวิธีที่ฉันใช้ (ฉันปล่อยให้คลาสจัดการกับ onStatusChanged):

private void startLocationTracking() {
    final int updateTime = 2000; // ms
    final int updateDistance = 10; // meter
    final Criteria criteria = new Criteria();
    criteria.setCostAllowed(false);
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    final String p = locationManager.getBestProvider(criteria, true);
    locationManager.requestLocationUpdates(p, updateTime, updateDistance,
            this);
}

และฉันจัดการ onStatusChanged ดังนี้:

void onStatusChanged(final String provider, final int status,
        final Bundle extras) {
    switch (status) {
    case LocationProvider.OUT_OF_SERVICE:
        if (location == null || location.getProvider().equals(provider)) {
            statusString = "No Service";
            location = null;
        }
        break;
    case LocationProvider.TEMPORARILY_UNAVAILABLE:
        if (location == null || location.getProvider().equals(provider)) {
            statusString = "no fix";
        }
        break;
    case LocationProvider.AVAILABLE:
        statusString = "fix";
        break;
    }
}

โปรดทราบว่าวิธีการ onProvider {Dis, En} abled () เกี่ยวกับการเปิดใช้งานและปิดใช้งานการติดตาม GPS โดยผู้ใช้ ไม่ใช่สิ่งที่คุณกำลังมองหา


น่าเสียดายที่มักไม่ได้ผล onLocationChanged () ถูกเรียกหนึ่งครั้งต่อวินาที แต่ onStatusChanged ไม่ถูกเรียกเลย บางครั้งฉันก็หวังว่าจะสามารถค้นหาสถานะปัจจุบันแทนที่จะรอการแจ้งเตือนที่อาจจะไม่มาเป็นเวลานานหรือเลยทีเดียว
Edward Falk

2
ขวา. ฉันได้เรียนรู้บางสิ่งด้วยตัวเองหลังจากการตอบกลับครั้งก่อนและสิ่งหนึ่งคือไม่ใช่ทุกแพลตฟอร์ม Android ที่สร้างขึ้นมาเหมือนกัน ฉันเห็นการโทรไปที่ onStatusChanged ทั้งบน HTC Hero และ Archos 5 ของฉันอย่างแน่นอน แต่ฉันไม่แปลกใจเลยที่ใช้ไม่ได้ทุกที่ วิธีการเกี่ยวกับแผน B: คุณใช้ GPSStatusListener ที่แสดงในคำตอบอื่นและดูว่าดาวเทียมใดส่งคืนจริงสำหรับ usedInFix () หรือไม่ จากประสบการณ์ของฉันที่ใกล้เคียงที่สุดกับพฤติกรรมของไอคอน GPS มาตรฐาน (คุณพยายามค้นหาแหล่งที่มาที่ใช้ไอคอนมาตรฐานนั้นหรือไม่ BTW)
CvR

0

การตั้งช่วงเวลาเพื่อตรวจสอบการแก้ไขไม่ใช่ทางเลือกที่ดี .. ฉันสังเกตว่าonLocationChanged ไม่ถูกเรียกหากคุณไม่ได้ย้าย .. สิ่งที่เข้าใจได้เนื่องจากตำแหน่งไม่ได้เปลี่ยน :)

วิธีที่ดีกว่าคือ:

  • ตรวจสอบช่วงเวลาไปยังตำแหน่งสุดท้ายที่ได้รับ (ใน gpsStatusChanged)
  • หากช่วงเวลานั้นมากกว่า 15 วินาทีตัวแปรที่ตั้งไว้: long_interval = true
  • ลบตัวฟังตำแหน่งและเพิ่มอีกครั้งโดยปกติแล้วคุณจะได้รับตำแหน่งที่อัปเดตหากตำแหน่งนั้นว่างจริงๆถ้าไม่ - คุณอาจสูญเสียตำแหน่ง
  • ใน onLocationChanged คุณเพิ่งตั้งค่า long_interval เป็นเท็จ ..
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.