定期接收位置更新

时间:2015-07-22 08:06:06

标签: java android multithreading

我正在编写一个应用程序来获取每5秒的位置。我收到了这个错误。 java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序。 我搜索了这个错误代码。许多人说需要创建runOnUiThread()。但是,即使我注释掉editTextShowLocation,意味着输出到ui,也会发生同样的错误。

非常感谢需要帮助的人。谢谢。

以下是我的代码:

package com.example.celine.telemetryloop;

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

    private EditText editTextShowLocation;
    private Button buttonGetLocation;

    private LocationManager locManager;
    private LocationListener locListener = new MyLocationListener();

    private boolean gps_enabled = false;
    private boolean network_enabled = false;
    String TAG = "App";

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextShowLocation = (EditText) findViewById(R.id.editTextShowLocation);

        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

        Thread rcvLocationThread = new Thread(new RcvLocation());
        rcvLocationThread.start();
    }


    class RcvLocation implements Runnable {
        public void run() {
            try {
                gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            } catch (Exception ex) {
            }
            try {
                network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            } catch (Exception ex) {
            }

            // don't start listeners if no provider is enabled
            if (!gps_enabled && !network_enabled) {
                Log.d(TAG, "Not Enabled!"); //to enable it for user.
            }

            if (gps_enabled) {
                locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
            }
            if (network_enabled) {
                locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class MyLocationListener extends Handler implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            Log.d(TAG, "2");
            if (location != null) {
                // This needs to stop getting the location data and save the battery power.
                //locManager.removeUpdates(locListener);

                String londitude = "Londitude: " + location.getLongitude();
                String latitude = "Latitude: " + location.getLatitude();
                String altitiude = "Altitiude: " + location.getAltitude();
                String accuracy = "Accuracy: " + location.getAccuracy();
                String time = "Time: " + location.getTime();

                editTextShowLocation.setText(londitude + "\n" + latitude + "\n" + altitiude + "\n" + accuracy + "\n" + time);
            }
        }

        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub

        }
    }
}

2 个答案:

答案 0 :(得分:0)

该错误实际上说该怎么做:Looper.prepare()尚未在您的线程中调用。请参阅此SO答案:https://stackoverflow.com/a/16886486/798406

它基本上表示您必须将Looper.prepare()放在Runnable的run()方法中。但是,您应该避免使用Thread.sleep。相反,您可以使用另一个处理程序并在5秒后发布延迟消息:

private class Poller implements Runnable {

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        // Do something

        long pollingDelay = 5000;
        mHandler.postDelayed(this, pollingDelay);
    }
}

// Start the handler
mPollingRunnable = new Poller();
mHandler.post(mPollingRunnable);

答案 1 :(得分:0)

首先,您错误地考虑了位置API - 您不需要每5秒轮询一次更新。您告诉LocationManager您要监听更新,它会在每次发生更新时告诉您更新。如果你告诉它将你的更新限制为每5秒一次,它将忽略或延迟更新以满足你的要求,但是如果没有任何给出,它会每隔五秒询问一次它会更频繁地给你更新

其次,你写的代码实际上并不是每五秒钟做一次。你开始的Thread只是注册更新,等待五秒,然后退出 - 没有循环发生。幸运的是,除了不必要的额外线程和5秒延迟之外,实际上 是使用Location API的正确方法。

最后,对于您的实际问题:您获得RuntimeException的原因是您为LocationManager提供了一个LocationListener并告诉它(无意中)在rcvLocationThread上执行其回调方法。 Looper是一个用作消息泵的类。 LooperThread之上运行,并执行Handler s给他们的工作。 HandlerLooper之上运行并接收消息和/或Runnable,以及Looper泵通过Handler的队列并执行每个传入的物品。

如果在调用Looper时未指定requestLocationUpdates,则LocationManager会假定您正在通过 Looper线程进行调用尝试将LocationListener方法调用排入同一个线程。由于你的线程没有运行Looper(在这种情况下它不应该),它实际上不能将回调排入队列,因此抛出异常。

那么 - 你做什么的?摆脱所有Thread废话,并将RcvLocation.run()方法中的所有内容放在new Thread(...).start()末尾的onCreate。此外,您的MyLocationListener课程不需要延长Handler - 只需让它实施LocationListener,您就可以了。回调将在主线程(已经拥有自己的Looper)上执行。这很好,因为你正在修改视图(必须从主线程完成的事情)并且看起来很安全,因为你没有进行任何长时间运行的处理操作。

public class MainActivity extends Activity {

    ... // variables and such

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextShowLocation = (EditText) findViewById(R.id.editTextShowLocation);

        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

        setupLocationUpdates();
    }


    private void setupLocationUpdates() {
        try {
            gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception ex) { /* tsk tsk, empty catch block */ }
        try {
            network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ex) { /* tsk tsk, empty catch block */ }

        // don't start listeners if no provider is enabled
        if (!gps_enabled && !network_enabled) {
            Log.d(TAG, "Not Enabled!"); //to enable it for user.
        }

        if (gps_enabled) {
            locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
        }
        if (network_enabled) {
            locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
        }
    }

    class MyLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            // do your stuff
        }

        // all the other required callback methods
    }
}