GeoCoder AsyncTask no actualiza TextView en segundo plano

Escenario:

Entonces, lo que he hecho hasta ahora es crear una AsyncTask para manejar mi GeoCoder que se actualiza cada 3 minutos (con fines de prueba). Luego configuré un TimerTask que muestra un mensaje de brindis con la dirección actual de los usuarios cada 4 minutos. (TimerTasks no incluido en el código)

Así que aquí está el problema:

Cuando estoy en mi aplicación, todo está bien, sin embargo, cuando mi aplicación se ejecuta en segundo plano, los mensajes de Toast permanecen atascados en la última dirección en la que se configuró la aplicación antes de salir de ella. Sé con certeza que AsyncTask se ejecuta en segundo plano (Checked LogCats) y parece que todo funciona bien en segundo plano, simplemente no puedo mostrar la dirección actual en mi Toast.

¡Todos los pensamientos y aportes serán apreciados!

Aquí está mi código:

 public class statuspage extends MapActivity {

LocationManager locationManager;
MapView mapView;
Criteria criteria;
Location location;
Geocoder gc;
Address address;

String bestProvider;
String LOCATION_SERVICE = "location";
String addressString = "Searching for Nearest Address";
StringBuilder sb;

private MapController mapController;
private MyLocationOverlay myLocation;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.statuspage);

    // Get Mapping Controllers etc //
    mapView = (MapView) findViewById(R.id.mapView);
    mapController = mapView.getController();
    mapController.setZoom(17);
    mapView.setBuiltInZoomControls(true);

    // Add the MyLocationOverlay //
    myLocation = new MyLocationOverlay(this, mapView);
    mapView.getOverlays().add(myLocation);
    myLocation.enableCompass();
    myLocation.enableMyLocation();

    // Animates the map to GPS Position //
    myLocation.runOnFirstFix(new Runnable() {
        @Override
        public void run() {
            mapController.animateTo(myLocation.getMyLocation());

        }
    });
}

@Override
protected boolean isRouteDisplayed() {

    // Location Manager Intiation
    locationManager = (LocationManager) statuspage.this
            .getSystemService(LOCATION_SERVICE);
    criteria = new Criteria();

    // More accurate, GPS fix.
    criteria.setAccuracy(Criteria.ACCURACY_FINE); // More accurate, GPS fix.
    bestProvider = locationManager.getBestProvider(criteria, true);

    location = locationManager.getLastKnownLocation(bestProvider);
    updateWithNewLocation(location);

    locationManager.requestLocationUpdates(bestProvider, 60000, 10,
            locationListener); // 1800000 = 30 Min

    return false;
}

class GeoCoder extends AsyncTask<Void, Void, Void> {

    String lat = "Acquiring";
    String lng = "Acquiring";

    @Override
    protected Void doInBackground(Void... params) {
        if (location != null) {

            /**
             * double latitude = myLocation.getMyLocation().getLatitudeE6();
             * double longitude =
             * myLocation.getMyLocation().getLongitudeE6();
             */

            double latitude = location.getLatitude();
            double longitude = location.getLongitude();

            lat = "" + latitude;
            lng = "" + longitude;

            // gc = new Geocoder(statuspage.this, Locale.getDefault());
            Geocoder gc = new Geocoder(getApplicationContext(),
                    Locale.getDefault());
            try {

                List<Address> addresses = gc.getFromLocation(latitude,
                        longitude, 1);

                sb = new StringBuilder();
                if (addresses != null && addresses.size() > 0) {
                    address = addresses.get(0);

                    int noOfMaxAddressLine = address
                            .getMaxAddressLineIndex();
                    if (noOfMaxAddressLine > 0) {
                        for (int i = 0; i < address
                                .getMaxAddressLineIndex(); i++) {
                            sb.append(address.getAddressLine(i)).append(
                                    "\n");
                        }
                        addressString = sb.toString();

                    }
                }
            } catch (Exception e) {

                addressString = "Sorry, we are trying to find information about this location";
            }

        }
        return null;
    }


    @Override
    protected void onPostExecute(Void result) {
        TextView scrollview = (TextView) findViewById(R.id.scrollview);

        // Latitude and Longitude TextView
        TextView etlongitude = (TextView) findViewById(R.id.etlongitude);
        TextView etlatitude = (TextView) findViewById(R.id.etlatitude);

        // TextView to display GeoCoder Address
        scrollview.setGravity(Gravity.CENTER);
        scrollview.setText("Your location:" + "\n"
                + "(Accurate to 500 meters)" + "\n" + (addressString));

        Log.d("Address", (addressString));

        // Latitude and Longitude TextView Display Coordinates //
        etlongitude.setText(lng);
        etlatitude.setText(lat);

        // Log.d("GeoCoder", "In-Task");

        return;
    }

preguntado el 03 de mayo de 12 a las 16:05

2 Respuestas

Cuando está utilizando una tarea asíncrona, no puede actualizar la interfaz de usuario en segundo plano. Es imposible conectar la interfaz de usuario desde el hilo interno que está en segundo plano. La única forma de conectar la interfaz de usuario es usar onPostExecute(). Y use esta función onPostExecute() para actualizar la interfaz de usuario. Intente enviar mensajes desde el fondo y haga las cosas de la interfaz de usuario en la ejecución posterior al verificar los mensajes. Esto lo ayudará con seguridad.

contestado el 04 de mayo de 12 a las 04:05

Gracias señor, trataré de investigar un poco sobre esto. ¿Podría darme un enlace que pueda explicar esto con más detalles? - Juan Nguyen

He tenido el mismo problema. Si me quedo en la actividad actual, no hay problema, pero si dejo la actividad mientras doInBackgroud Esta corriendo, onPostExecute saldrá en la línea Toast.

Para resolver el problema, debe usar un controlador:
En la clase

private static final int TOAST  = 0;
private Handler mHandler = null;

In OnCreate()

// Creation of the handler to display Toasts
if (mHandler == null) {
    mHandler = new Handler() {
        @Override
        public void handleMessage(Message _msg) {
            switch (_msg.what) {
            case TOAST:
            Toast.makeText(ServerTabHost.this, (String)_msg.obj, Toast.LENGTH_LONG).show();
            break;
            default : break;
        }
        super.handleMessage(_msg);
        }
    };
}

In onPostExecute()

Message msg = new Message();
msg.what = TOAST;
msg.obj = "my toast message";
mHandler.sendMessage(msg);

En tu código se ve así:

public class statuspage extends MapActivity {

// These two lines are for the handler
private static final int TOAST  = 0;
private Handler mHandler = null;

LocationManager locationManager;
MapView mapView;
Criteria criteria;
Location location;
Geocoder gc;
Address address;

String bestProvider;
String LOCATION_SERVICE = "location";
String addressString = "Searching for Nearest Address";
StringBuilder sb;

private MapController mapController;
private MyLocationOverlay myLocation;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.statuspage);

    // Get Mapping Controllers etc //
    mapView = (MapView) findViewById(R.id.mapView);
    mapController = mapView.getController();
    mapController.setZoom(17);
    mapView.setBuiltInZoomControls(true);

    // Add the MyLocationOverlay //
    myLocation = new MyLocationOverlay(this, mapView);
    mapView.getOverlays().add(myLocation);
    myLocation.enableCompass();
    myLocation.enableMyLocation();

    // Animates the map to GPS Position //
    myLocation.runOnFirstFix(new Runnable() {
        @Override
        public void run() {
            mapController.animateTo(myLocation.getMyLocation());

        }
    });

    // Creation of the handler to display Toasts
    if (mHandler == null) {
        mHandler = new Handler() {
        @Override
        public void handleMessage(Message _msg) {
            switch (_msg.what) {
                case TOAST:
                Toast.makeText(ServerTabHost.this, (String)_msg.obj, Toast.LENGTH_LONG).show();
                break;
                default : break;
            }
            super.handleMessage(_msg);
            }
        };
    }
}

@Override
protected boolean isRouteDisplayed() {

    // Location Manager Intiation
    locationManager = (LocationManager) statuspage.this
            .getSystemService(LOCATION_SERVICE);
    criteria = new Criteria();

    // More accurate, GPS fix.
    criteria.setAccuracy(Criteria.ACCURACY_FINE); // More accurate, GPS fix.
    bestProvider = locationManager.getBestProvider(criteria, true);

    location = locationManager.getLastKnownLocation(bestProvider);
    updateWithNewLocation(location);

    locationManager.requestLocationUpdates(bestProvider, 60000, 10,
            locationListener); // 1800000 = 30 Min

    return false;
}

class GeoCoder extends AsyncTask<Void, Void, Void> {

    String lat = "Acquiring";
    String lng = "Acquiring";

    @Override
    protected Void doInBackground(Void... params) {
        if (location != null) {

            /**
             * double latitude = myLocation.getMyLocation().getLatitudeE6();
             * double longitude =
             * myLocation.getMyLocation().getLongitudeE6();
             */

            double latitude = location.getLatitude();
            double longitude = location.getLongitude();

            lat = "" + latitude;
            lng = "" + longitude;

            // gc = new Geocoder(statuspage.this, Locale.getDefault());
            Geocoder gc = new Geocoder(getApplicationContext(),
                    Locale.getDefault());
            try {

                List<Address> addresses = gc.getFromLocation(latitude,
                        longitude, 1);

                sb = new StringBuilder();
                if (addresses != null && addresses.size() > 0) {
                    address = addresses.get(0);

                    int noOfMaxAddressLine = address
                            .getMaxAddressLineIndex();
                    if (noOfMaxAddressLine > 0) {
                        for (int i = 0; i < address
                                .getMaxAddressLineIndex(); i++) {
                            sb.append(address.getAddressLine(i)).append(
                                    "\n");
                        }
                        addressString = sb.toString();

                    }
                }
            } catch (Exception e) {

                addressString = "Sorry, we are trying to find information about this location";
            }

        }
        return null;
    }


    @Override
    protected void onPostExecute(Void result) {

        // Sending the Toast message through the handler
        Message msg = new Message();
    msg.what = TOAST;
    msg.obj = "My toast message";
    mHandler.sendMessage(msg);

        TextView scrollview = (TextView) findViewById(R.id.scrollview);

        // Latitude and Longitude TextView
        TextView etlongitude = (TextView) findViewById(R.id.etlongitude);
        TextView etlatitude = (TextView) findViewById(R.id.etlatitude);

        // TextView to display GeoCoder Address
        scrollview.setGravity(Gravity.CENTER);
        scrollview.setText("Your location:" + "\n"
                + "(Accurate to 500 meters)" + "\n" + (addressString));

        Log.d("Address", (addressString));

        // Latitude and Longitude TextView Display Coordinates //
        etlongitude.setText(lng);
        etlatitude.setText(lat);

        // Log.d("GeoCoder", "In-Task");

        return;
    }

Personalmente, estaba en un Fragmento, así que tuve que crear el controlador en la actividad del host y luego pasarlo al constructor del fragmento.

contestado el 04 de mayo de 12 a las 09:05

Nunca antes había tratado con Handlers. Gracias por la ayuda y orientación. Estoy investigando controladores ahora para entenderlo mejor. Hasta ahora, lo que ha sugerido parece estar funcionando a mi gusto. ¡Gracias, Elasticboy! - Juan Nguyen

Lo siento si mi pregunta fue un poco engañosa. Los mensajes de brindis aparecen bien, solo cuando no estoy en mi aplicación (navegando por la web, por ejemplo) mi mensaje de brindis permanecerá atascado en la dirección que me proporcionó cuando estaba en mi actividad actual y seguirá mostrándome que misma dirección hasta que vuelva a mi aplicación. La dirección no se actualiza hasta que volví a mi Actividad. - Juan Nguyen

Entonces, el mensaje de brindis se muestra pero con una información obsoleta, ¿es eso? - cirilo leroux

Sí, tiene usted razón. Creo que podría haberlo hecho funcionar usando runOnUiThread dentro de mi AsyncTask. Lo estoy probando mientras hablamos. Si tiene alguna otra idea o información adicional, ¡comparta! - Juan Nguyen

No veo la llamada de mensaje Toast en el código que publicaste. ¿Puedes publicar esta parte? Eso podría ayudarme a entender por qué no funciona. - cirilo leroux

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.