在 Android 上的后台线程中运行 GPS 定位

发布于 2024-12-02 12:19:48 字数 4175 浏览 1 评论 0原文

我有一个奇怪的问题,在我的应用程序中,GPS 定位需要相当长的时间(通常如此),因此我想在用户在其他视图中做出选择时将其作为自己的线程运行。

我的结构是,我有一个始终在后台活动的“主”视图,然后向用户显示一系列视图,他或她在其中做出一些选择。最后,用户会看到基于所做选择和当前位置的结果。所有这些都有效,但我想将 GPS 位移至其自己的线程,以便用户不必等待它完成。

所有用户的选择和 GPS 坐标都存储在名为 CurrentLogEntry 的单例中。程序不同部分之间的所有通信都是通过它来执行的。

我在主视图中创建了一个 handleMessage(Message msg) 重写,然后在 Main.java 中实现了该函数:

void startGPSThread() {
    Thread t = new Thread() {

        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);     
        boolean isDebug = CurrentLogEntry.getInstance().isDebug();

        // Define a listener that responds to location updates
        LocationListener locationListener  = new LocationListener() {

            public void onStatusChanged(String provider, int status, Bundle extras) {
                /* This is called when the GPS status changes */
                String tag = "onStatusChanged, ";
                switch (status) {
                    case LocationProvider.OUT_OF_SERVICE:
                        Log.w(tag, "Status Changed: Out of Service");
                        break;
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        Log.w(tag, "Status Changed: Temporarily Unavailable");
                        break;
                    case LocationProvider.AVAILABLE:
                        break;
                }
            }

            public void onProviderEnabled(String provider) {
            }

            public void onProviderDisabled(String provider) {
                // This is called if the GPS is disabled in settings.
                // Bring up the GPS settings
                Intent intent = new Intent(
                        android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);
            }

            public void onLocationChanged(Location location) {

                // Once a location has been received, ignore all other position
                // updates.
                locationManager.removeUpdates(locationListener);
                locationManager.removeUpdates(this);

                // Make sure that the received location is a valid one,
                // otherwise show a warning toast and hit "back".
                if (location == null) {
                    String warningString = "Location was unititialized!";

                    if (isDebug) {
                        Toast.makeText(getApplicationContext(),
                                warningString,
                                Toast.LENGTH_LONG).show();
                    }

                    KeyEvent kev = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
                    onKeyDown(KeyEvent.KEYCODE_BACK, kev);
                }

                CurrentLogEntry.getInstance().setUserLatitude(location.getLatitude());
                CurrentLogEntry.getInstance().setUserLongitude(location.getLongitude());

                //Send update to the main thread
                int result = 0;
                if (location.getLatitude() == 0 || location.getLongitude() == 0) {
                    result = -1;
                }

                messageHandler.sendMessage(Message.obtain(messageHandler, result));
            }
        };

        @Override
        public void run() {

            locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, 0, 0, locationListener);

            // Wait until a position has bee acquired.
            while(!CurrentLogEntry.getInstance().isReadyToCalculate()){
                try {
                    wait(250);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    };

    t.start();
}

该函数在 Main.onCreate() 中调用。

不幸的是,这根本不起作用。程序一到达 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); 就崩溃了,这让我完全难住了。

谁能告诉我为什么这不会作为后台线程运行?另外,我真的需要在最后进行等待轮询以确保线程在收到数据之前保持活动状态吗?在我想将 GPS 位放入自己的线程之前,它工作得很好,所以我到底做错了什么?

I have curious problem, in my application, the GPS-positioning takes quite a long time (as it tends to do) and therefore I wanted to run it as its own thread while the user is making choices in other views.

My structure is that I have a "main" view that is always active in the background, then the user is shown a series of views in which he or she makes a few choices. In the end, the user is presented with a result based on the choices made and the current position. All of this works, but I wanted to move the GPS-bit to its own thread so that the user wouldn't have to wait for it to finish.

All of the user's choices and the GPS coordinates is stored in a singleton called CurrentLogEntry. All communication between the different parts of the program is performed through it.

I created a handleMessage(Message msg) override in the main view and then I implemented this function in Main.java:

void startGPSThread() {
    Thread t = new Thread() {

        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);     
        boolean isDebug = CurrentLogEntry.getInstance().isDebug();

        // Define a listener that responds to location updates
        LocationListener locationListener  = new LocationListener() {

            public void onStatusChanged(String provider, int status, Bundle extras) {
                /* This is called when the GPS status changes */
                String tag = "onStatusChanged, ";
                switch (status) {
                    case LocationProvider.OUT_OF_SERVICE:
                        Log.w(tag, "Status Changed: Out of Service");
                        break;
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        Log.w(tag, "Status Changed: Temporarily Unavailable");
                        break;
                    case LocationProvider.AVAILABLE:
                        break;
                }
            }

            public void onProviderEnabled(String provider) {
            }

            public void onProviderDisabled(String provider) {
                // This is called if the GPS is disabled in settings.
                // Bring up the GPS settings
                Intent intent = new Intent(
                        android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);
            }

            public void onLocationChanged(Location location) {

                // Once a location has been received, ignore all other position
                // updates.
                locationManager.removeUpdates(locationListener);
                locationManager.removeUpdates(this);

                // Make sure that the received location is a valid one,
                // otherwise show a warning toast and hit "back".
                if (location == null) {
                    String warningString = "Location was unititialized!";

                    if (isDebug) {
                        Toast.makeText(getApplicationContext(),
                                warningString,
                                Toast.LENGTH_LONG).show();
                    }

                    KeyEvent kev = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
                    onKeyDown(KeyEvent.KEYCODE_BACK, kev);
                }

                CurrentLogEntry.getInstance().setUserLatitude(location.getLatitude());
                CurrentLogEntry.getInstance().setUserLongitude(location.getLongitude());

                //Send update to the main thread
                int result = 0;
                if (location.getLatitude() == 0 || location.getLongitude() == 0) {
                    result = -1;
                }

                messageHandler.sendMessage(Message.obtain(messageHandler, result));
            }
        };

        @Override
        public void run() {

            locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, 0, 0, locationListener);

            // Wait until a position has bee acquired.
            while(!CurrentLogEntry.getInstance().isReadyToCalculate()){
                try {
                    wait(250);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    };

    t.start();
}

This function is called in Main.onCreate().

Unfortunately, this doesn't work at all. The program crashes as soon as it reaches locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); and that has me completely stumped.

Can anyone enlighten me as to why this won't run as a background thread? Also, do I really need the wait-polling at the end to ensure that the thread stays alive until it receives its data? The GPS bit worked just fine before I wanted to put it in a thread of its own, so what in the world am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

全部不再 2024-12-09 12:19:48

据我了解,您必须使线程成为 Looper 线程才能在后台运行位置更新...但是我仍在尝试自己解决这个问题...当我弄清楚如何执行此操作时,我将发布它。

可能有与我收到的相同的错误,即无法在未调用 Looper.prepare() 的线程中创建处理程序

希望你能让它正常工作。

From what i understand you have to make the Thread a Looper thread in order to run Location Updates in the background...however i am still trying to figure this out myself...when i figure out how to do this i will post it.

Probably have the same error that i received, which is can't create handler in thread where Looper.prepare() has not been called

Hope you get it working bud

毁我热情 2024-12-09 12:19:48

检查线程,专门针对这个答案。它们处理相同的主题、位置和相同的问题,从线程循环中运行。

Check the this thread and specifically for this answer. They deal with the same subject, location, and the same problem, running it from a Thread loop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文