質問

I'm trying to make a trivial application in which the user clicks a button and a few text views display various information about the phone(model,battery %,location,signal strength etc). I'm having trouble getting the current latitude and longitude, since when I press the button the textview displays the previous latitude/longitude(first time it shows 0,0 and the second the position I was when I first pressed it).

What I'm trying to achieve is when I press the button, activate the location manager and location listener, and make the onClick() method wait until the latitude is not equal to the old latitude. I've tried Threads, handler, and asynctask but I haven't managed anything. Any tips? This is how my onClick() method looks right now: (Infogatherer is a class where I collect all the info)

    @Override
public void onClick(View arg0) {
    // TODO Auto-generated method stub
    switch(arg0.getId()){
    case R.id.bMeasurements:

        oldLat=InfoGatherer.getLatitude();
        oldLong=InfoGatherer.getLongitude();

            //SOMEWHERE HERE START A THREAD OR SOMETHING IN ORDER TO RETRIEVE CURRENT LOCATION
        //Retrieval and Assignment of information to the corresponding text fields
        DeviceName.setText(infogatherer.getDeviceName());

        NetworkOp.setText(infogatherer.getNetworkOp());

        Date.setText(infogatherer.getDate());

        BatteryStatus.setText(String.valueOf(infogatherer.getBatteryStatus()));

        Generation.setText(String.valueOf(infogatherer.getGeneration()));   
        infogatherer.getLocation();
        Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
        infogatherer.getSignalStrength();
        SignalStrength.setText(String.valueOf(infogatherer.getDbm()));

        oldLat = InfoGatherer.getLatitude();
        oldLong = InfoGatherer.getLongitude();
        break;

    }

This is my InfoGatherer class:

package com.example.netmap;

import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.telephony.CellInfoGsm;
import android.telephony.CellSignalStrengthGsm;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;

public class InfoGatherer extends Application{

    String address,city,country;
    int cid,lac,generation=0,ipAddress=0,signalStrngth=0;
    private GsmCellLocation location;
    private WifiInfo wifiInfo;
    private LocationManager lm;
    private LocationListener ll;
    Geocoder geoc;
    static public double Longitude,Latitude=0;
    List<Address> addresses;
    Context context;
    Intent batteryIntent;
    TelephonyManager tm;
    WifiManager wifimanager;

    public InfoGatherer(){

    }
    public InfoGatherer(Context context){
        this.context = context;
    }

    public String getDate(){
        Calendar c = Calendar.getInstance();
        return Integer.toString(c.get(Calendar.DAY_OF_MONTH))+"-"+Integer.toString(c.get(Calendar.MONTH))+"-"+Integer.toString(c.get(Calendar.YEAR))+"    "+Integer.toString(c.get(Calendar.HOUR_OF_DAY))+":"+Integer.toString(c.get(Calendar.MINUTE))+":"+Integer.toString(c.get(Calendar.SECOND));
    }

    public String getDeviceName(){
        return Build.MANUFACTURER +" "+Build.MODEL;
    }

    public String getNetworkOp(){
        tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        return tm.getNetworkOperatorName();

    }

    public float getBatteryStatus() {
        batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        return ((float)batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) / (float)batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)) * 100.0f;
    }


    public int getGeneration(){
        tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        return tm.getNetworkType();
    }

     public int getCid(){
        tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        location = (GsmCellLocation)tm.getCellLocation();
        return location.getCid();
    }

    public int getLac(){
        tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        location = (GsmCellLocation)tm.getCellLocation();
        return location.getLac();
    }

    public String getIpAddress() {
        // TODO Auto-generated method stub
        wifimanager = (WifiManager) context.getSystemService(WIFI_SERVICE);
        wifiInfo = wifimanager.getConnectionInfo();
        ipAddress = wifiInfo.getIpAddress();
        return String.format("%d.%d.%d.%d",(ipAddress & 0xff),(ipAddress >> 8 & 0xff),(ipAddress >> 16 & 0xff),(ipAddress >> 24 & 0xff));
    }

    public void getLocation(){
        /*Criteria c = new Criteria();
        c.setAccuracy(Criteria.ACCURACY_FINE);
        c.setPowerRequirement(Criteria.POWER_LOW);
        String provider = lm.getBestProvider(c, true);*/

        lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
        ll = new mylocationlistener();

        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);

    }

    public class mylocationlistener implements LocationListener{

        @Override
        public void onLocationChanged(android.location.Location location) {
            // TODO Auto-generated method stub
            if(location!=null){
                Longitude = location.getLongitude();
                Latitude = location.getLatitude();

                lm.removeUpdates(ll);

            }

        }



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

            //Pass views as parameters? DIscuss
            //DeviceName.setText(String.valueOf(Latitude) +" "+String.valueOf(Longitude));

        }

        @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

        }

    }

    public void getSignalStrength(){
        tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener Listener = new phoneStateListener();
        tm.listen(Listener ,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
    }

    public class phoneStateListener extends PhoneStateListener{
        public void onSignalStrengthsChanged(SignalStrength signalStrength){
            super.onSignalStrengthsChanged(signalStrength);
            if (signalStrength.isGsm()) {
                signalStrngth = -113 + 2 * signalStrength.getGsmSignalStrength();

            }
            else
                signalStrngth = -113 + 2 * signalStrength.getCdmaDbm();
        }

    }





    static public double getLatitude(){
        return Latitude;
    }

    static public double getLongitude(){
        return Longitude;
    }

    public String getAddress(){
        return address;
    }

    public String getCity(){
        return city;
    }

    public String getCountry(){
        return country;
    }

    public int getDbm(){
        return signalStrngth;
    }

}
役に立ちましたか?

解決 3

In the end I used AsyncTask, which helped me in order to sleep the app while I looked for the location.

private class LocationThread extends AsyncTask<Context, Void, Void> {

    protected void onPreExecute() {
        infogatherer.startLocationListener();
    }

    @Override
    protected Void doInBackground(Context... params) {
        while (!infogatherer.getGo()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    protected void onPostExecute(final Void unused) {
        //Do whatever you wanna do after you get location
    }
}

getGo is a boolean which whenever becomes true gives the location back

public class mylocationlistener implements LocationListener {
    @Override
    public void onLocationChanged(android.location.Location location) {
        if(location != null){
            Longitude = location.getLongitude();
            Latitude = location.getLatitude();
            lm.removeUpdates(ll);
            go = true;
        }
    }

hope you understand the procedure. Cheers.

他のヒント

You don´t provide enough time to Location service get the location.
You ask for latitude and longitude before the LocationManager have time to call onLocationChanged.

infogatherer.getLocation();
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));

Call infogatherer.getLocation(); out of onClick event. Do that at Activity onResume() event.
Remove lm.removeUpdates(ll); from onLocationChanged. Call it at Activity onPause()event.

If you want see this example how to create a GPS Manager Class

EDIT
Try something like this: Note: Not tested!

private void updateLocationText(double oldLat, double oldLong) {
    Handler handler = new Handler();
    Runnable runnable = new Runnable() {

        public void run() {
            boolean isPositionChanged = false;
            double lat;
            double long;
            while (!isPositionChanged) {  
                lat = InfoGatherer.getLatitude();
                long = InfoGatherer.getLongitude();
                if(lat != oldLat || long != oldLong)isPositionChanged = true;
            }
            handler.post(new Runnable(){
                public void run() {
                    Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
                });
            }
        }
    };
    new Thread(runnable).start();
}  

Note that if you click on the button without having been no change of location, it will run forever.

EDIT AGAIN

Another approach more clean:

Replace

Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));  

with this

Location.postDelayed(new Runnable() {
    @Override
    public void run() {
        Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
        Location.postInvalidate();//Try without, may be not necessary
    }
}, 3000);//Change if need

Create the LocationListener out of Aplication. In the Ativity instantiate the class, override the onLocationChanged event and update Location TextView there.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    .........
    .........
    lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    listener = new MyLocationListener(){
        @Override
        public void onLocationChanged(android.location.Location location) {
            if(location!=null){
                Location.setText(String.valueOf(location.getLatitude()+","+location.getLatitude()));
                lm.removeUpdates(listener);
            }
        }
    }
}  

In onClick() event replace:

infogatherer.getLocation();
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));

with

lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top