4

I am trying to refresh the current location through a click of a button. The location can be acquired via GPS or Cell Tower, whichever is available. My problem is I never see the "Loading Screen". I know it appears as something appears/closes instantly while the coordinates remain zero. Can somebody help me - what I am doing wrong below?

Neither the location is updated nor the loading screen appears. Without the loading screen and by multiple clicks of the "refresh button" I do get the location. Below is my code for handling clicks on the "Refresh Button":

FieldChangeListener refreshImgListener = new FieldChangeListener() {   
    public void fieldChanged(Field field, int context) 
    {
        Thread backgroundWorker = new Thread(new Runnable() {
            public void run() {
                refreshCoordinates();
            }
        });
        busyDialog.setEscapeEnabled(false);  
        busyDialog.show();
        backgroundWorker.start();
    }
};

And my refreshCoordinates() method is as below:

public void refreshCoordinates() {
    do
    {
        getLatitude(handleeGPS.latitude);
        getLongitude(handleeGPS.longitude);
    } while ((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));

    UiApplication.getUiApplication().invokeLater( new Runnable()
    {
        public void run ()
        {
            lblLatitude.setText(lati);
            lblLongitude.setText(longi);
            busyDialog.cancel();
        }
    } );
}

public static String getLatitude(double value) 
{
    lati= Double.toString(value);
    return lati;
}
public static String getLongitude(double value) 
{
    longi= Double.toString(value);
    return longi;
}

Class that returns the latitude and longitude values:

public class handleeGPS{

    static GPSThread gpsThread;
    public static double latitude;
    public static double longitude;

    public handleeGPS(){
        gpsThread = new GPSThread();
        gpsThread.start();
    }

    private static class GPSThread extends Thread{
        public void run() {
            Criteria myCriteria = new Criteria();
            myCriteria.setCostAllowed(false);
            int m_bbHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs");
            if(m_bbHandle>0){
                try {
                    int cellID = GPRSInfo.getCellInfo().getCellId();
                    int lac = GPRSInfo.getCellInfo().getLAC();
                    String urlString2 = "http://www.google.com/glm/mmap";
                    // Open a connection to Google Maps API
                    ConnectionFactory connFact = new ConnectionFactory();
                    ConnectionDescriptor connDesc;
                    connDesc = connFact.getConnection(urlString2);
                    HttpConnection httpConn2;
                    httpConn2 = (HttpConnection)connDesc.getConnection();
                    httpConn2.setRequestMethod("POST");
                    // Write some custom data to Google Maps API
                    OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
                    WriteDataGoogleMaps(outputStream2, cellID, lac);
                    // Get the response
                    InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
                    DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
                    // Interpret the response obtained
                    dataInputStream2.readShort();
                    dataInputStream2.readByte();
                    int code = dataInputStream2.readInt();
                    //Dialog.alert(code+"");
                    if (code == 0) {
                        latitude= dataInputStream2.readInt() / 1000000D;
                        longitude=dataInputStream2.readInt() / 1000000D;
                        //Dialog.alert(latitude+"-----"+longitude);
                        dataInputStream2.readInt();
                        dataInputStream2.readInt();
                        dataInputStream2.readUTF();
                    } else {
                        System.out.println("Error obtaining Cell Id ");
                    }
                    outputStream2.close();
                    inputStream2.close();
                } catch (Exception e) {
                    System.out.println("Error: " + e.getMessage());
                }
            } else {
                try {
                    LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
                    try {
                        Location myLocation = myLocationProvider.getLocation(300);
                        latitude  = myLocation.getQualifiedCoordinates().getLatitude();
                        longitude = myLocation.getQualifiedCoordinates().getLongitude();
                        if(latitude==0.0 && longitude==0.0){
                            try {
                                int cellID = GPRSInfo.getCellInfo().getCellId();
                                int lac = GPRSInfo.getCellInfo().getLAC();
                                String urlString2 = "http://www.google.com/glm/mmap";
                                // Open a connection to Google Maps API
                                ConnectionFactory connFact = new ConnectionFactory();
                                ConnectionDescriptor connDesc;
                                connDesc = connFact.getConnection(urlString2);
                                HttpConnection httpConn2;
                                httpConn2 = (HttpConnection)connDesc.getConnection();
                                httpConn2.setRequestMethod("POST");
                                // Write some custom data to Google Maps API
                                OutputStream outputStream2 = httpConn2.openOutputStream();
                                //getOutputStream();
                                WriteDataGoogleMaps(outputStream2, cellID, lac);
                                // Get the response
                                InputStream inputStream2 = httpConn2.openInputStream();
                                //getInputStream();
                                DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
                                // Interpret the response obtained
                                dataInputStream2.readShort();
                                dataInputStream2.readByte();
                                int code = dataInputStream2.readInt();
                                //Dialog.alert(code+"");
                                if (code == 0) {
                                    latitude= dataInputStream2.readInt() / 1000000D;
                                    longitude=dataInputStream2.readInt() / 1000000D;
                                    //Dialog.alert(latitude+"-----"+longitude);
                                    dataInputStream2.readInt();
                                    dataInputStream2.readInt();
                                    dataInputStream2.readUTF();
                                } else {
                                    System.out.println("Error obtaining Cell Id ");
                                }
                                outputStream2.close();
                                inputStream2.close();
                            } catch (Exception e) {
                                System.out.println("Error: " + e.getMessage());
                            }
                        }
                    }
                    catch ( InterruptedException iex ) {
                        return;
                    }
                    catch ( LocationException lex ) {
                        return;
                    }
                } catch ( LocationException lex ) {
                    return;
                }
            }
            return;
        }
    }

    private static void WriteDataGoogleMaps(OutputStream out, int cellID, int lac)
    throws IOException {
        DataOutputStream dataOutputStream = new DataOutputStream(out);
        dataOutputStream.writeShort(21);
        dataOutputStream.writeLong(0);
        dataOutputStream.writeUTF("en");
        dataOutputStream.writeUTF("Android");
        dataOutputStream.writeUTF("1.0");
        dataOutputStream.writeUTF("Web");
        dataOutputStream.writeByte(27);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(3);
        dataOutputStream.writeUTF("");
        dataOutputStream.writeInt(cellID);
        dataOutputStream.writeInt(lac);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.writeInt(0);
        dataOutputStream.flush();
    }
}
Nate
  • 31,017
  • 13
  • 83
  • 207
Sarah
  • 1,895
  • 2
  • 21
  • 39
  • thanks for posting the update. I see a couple problems with the `handleeGPS` class, but it's late for me, and I need to sleep. if someone else doesn't help you with this today, I'll write more tomorrow. – Nate Aug 14 '12 at 10:38
  • @Nate alright thanks. I'll work around myself too. Will wait for your feedback tomorrow. – Sarah Aug 14 '12 at 10:41

3 Answers3

5

Ok, so although my original answer was valid, the new code you posted has some different problems, so I'm posting a second answer. There were enough things that didn't look right, that I just rewrote your handleeGPS class. I'll explain the major changes I made, one-by-one:

  1. Try to use Java naming conventions. This makes it easier for us to help you. Before you posted the code to your handleeGPS class, I thought it was a variable, because lowercase names are usually used for variables, not classes.

  2. Avoid duplicating code. The handleeGPS class had a lot of code to read through, but most of it was the code to get location from Google's web service, which you duplicated in two places. Just make a method that contains only that code, and call it twice.

  3. I renamed your handleeGPS class to GPSHandler. I'm not sure if handlee was an error, or if that's a word in another language that you used. Anyway, the name should at least start with an uppercase letter.

  4. Avoid lots of static variables and methods. Sometimes, there really should be only one of something. A GPS handling class is probably a good example of that, because the device only has one GPS system. But, to enforce this code construct, don't mark everything as static. Just make the class a Singleton, which involves creating only one static member variable (_instance) and one static method (getInstance()). In my code, you will access the class like this: GPSHandler gps = GPSHandler.getInstance();.

  5. I believe the check you had for whether BB maps was installed was actually backwards. You looked up the net_rim_bb_lbs module, and if it was greater than zero (which means BB Maps is installed) then you went directly to the Google webservice. I think you want it the other way around (try device GPS if BB Maps installed). Also, since 6.0, you need to check for net_rim_bb_maps, too.

  6. Before you posted the update, I thought your getLatitude() and getLongitude() methods were actually fetching the device location. That was a bad assumption on my part. They were just converting numbers to strings. So, there's no reason for that to be done in the background (with a Thread). You already wrote your handleeGPS class to use a background thread, which is good. One background thread is enough. The UI that uses the location information should not also need a background Thread. I changed the code to add a GPSListener interface. That interface should be implemented by your UI code, to receive location updates. There is no reason to keep looping, asking if the location is not equal to {0.0, 0.0}. That's inefficient. With my code, you will just get notified when the location does change.

  7. The original code was not thread safe. The handleeGPS latitude and longitude variables were set on the background thread, and accessed on the UI thread. That's not safe. Two threads should not be reading and writing the same piece of data at once. By changing the code to push location data to the GPSListener, it avoids this problem.

  8. I uncommented the Dialog.alert() code you had inside your handleeGPS class, which would not have worked for you, because you're not allowed to make UI calls from the background. I surrounded those calls with UiApplication.getUiApplication().invokeLater() to make them safe.

To use this class, in your UI code somewhere, you would do this, instead of using a Thread to run your refreshCoordinates() method:

public void fieldChanged(Field field, int context) 
    // this is called when your location refresh button is clicked
    GPSHandler.getInstance().setListener(this); 
    GPSHandler.getInstance().requestLocationUpdates();
    busyDialog.setEscapeEnabled(false);  
    busyDialog.show();
}

...

public void onLocationReceived(Coordinates location) {
    lblLatitude.setText(Double.toString(location.getLatitude()));               
    lblLongitude.setText(Double.toString(location.getLongitude()));               
    busyDialog.cancel();               
}     

Make sure the class where you put that code (above) also implements GPSListener, which is an interface, defined here:

public interface GPSListener {
    public void onLocationReceived(Coordinates location);
}

and finally, the GPSHandler:

public class GPSHandler { 

   private GPSThread _gpsThread;
   private Coordinates _location;
   private boolean _gotLocation;
   private GPSListener _listener;

   /** this class will be a Singleton, as the device only has one GPS system */
   private static GPSHandler _instance;

   /** @return the Singleton instance of the GPSHandler */
   public static GPSHandler getInstance() {
      if (_instance == null) {
         _instance = new GPSHandler();
      }
      return _instance;
   }

   /** not publicly accessible ... use getInstance() */
   private GPSHandler() { 
   }

   /** call this to trigger a new location fix */
   public void requestLocationUpdates() {
       if (_gpsThread == null || !_gpsThread.isAlive()) {
          _gpsThread = new GPSThread();
          _gpsThread.start(); 
       }
   }

   public void setListener(GPSListener listener) {
      // only supports one listener this way
      _listener = listener;   
   }

   private void setLocation(final Coordinates value) {
      _location = value;
      if (value.getLatitude() != 0.0 || value.getLongitude() != 0.0) {
         _gotLocation = true;
         if (_listener != null) {
            // this assumes listeners are UI listeners, and want callbacks on the UI thread:
            UiApplication.getUiApplication().invokeLater(new Runnable() {
               public void run() {
                  _listener.onLocationReceived(value);
               }
            });
         }
      }
   }

   private class GPSThread extends Thread {

      private void getLocationFromGoogle() {
         try { 
            int cellID = GPRSInfo.getCellInfo().getCellId(); 
            int lac = GPRSInfo.getCellInfo().getLAC(); 

            String urlString2 = "http://www.google.com/glm/mmap"; 

            // Open a connection to Google Maps API  
            ConnectionFactory connFact = new ConnectionFactory(); 
            ConnectionDescriptor connDesc; 
            connDesc = connFact.getConnection(urlString2); 

            HttpConnection httpConn2; 
            httpConn2 = (HttpConnection)connDesc.getConnection(); 
            httpConn2.setRequestMethod("POST"); 

            // Write some custom data to Google Maps API  
            OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream(); 
            writeDataGoogleMaps(outputStream2, cellID, lac); 

            // Get the response   
            InputStream inputStream2 = httpConn2.openInputStream();//getInputStream(); 
            DataInputStream dataInputStream2 = new DataInputStream(inputStream2); 

            // Interpret the response obtained  
            dataInputStream2.readShort(); 
            dataInputStream2.readByte(); 

            final int code = dataInputStream2.readInt(); 
            UiApplication.getUiApplication().invokeLater(new Runnable() {
               public void run() {
                  Dialog.alert(code + "");   
               }
            });                        

            if (code == 0) { 
               final double latitude = dataInputStream2.readInt() / 1000000D; 
               final double longitude = dataInputStream2.readInt() / 1000000D; 
               setLocation(new Coordinates(latitude, longitude, 0.0f));

               UiApplication.getUiApplication().invokeLater(new Runnable() {
                  public void run() {
                     Dialog.alert(latitude+"-----"+longitude);   
                  }
               });

               dataInputStream2.readInt(); 
               dataInputStream2.readInt(); 
               dataInputStream2.readUTF(); 
            } else { 
               System.out.println("Error obtaining Cell Id "); 
            } 
            outputStream2.close(); 
            inputStream2.close(); 
         } catch (Exception e) { 
            System.out.println("Error: " + e.getMessage()); 
         } 
      }

      private void tryGetLocationFromDevice() {
         _gotLocation = false;
         try {
            Criteria myCriteria = new Criteria(); 
            myCriteria.setCostAllowed(false); 
            LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria); 

            try { 
               Location myLocation = myLocationProvider.getLocation(300); 
               setLocation(myLocation.getQualifiedCoordinates()); 
            } catch ( InterruptedException iex ) { 
               System.out.println(iex.getMessage());
            } catch ( LocationException lex ) { 
               System.out.println(lex.getMessage());
            } 
         } catch ( LocationException lex ) { 
            System.out.println(lex.getMessage());
         }

         if (!_gotLocation) { 
            getLocationFromGoogle();
         } 
      }

      public void run() { 
         int bbMapsHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs");    // OS < 6.0
         int bbMapsHandle60 = CodeModuleManager.getModuleHandle("net_rim_bb_maps"); // OS 6.0+
         if (bbMapsHandle > 0 || bbMapsHandle60 > 0) { 
            tryGetLocationFromDevice();
         } else {
            getLocationFromGoogle();
         }
      } 
   } 

   private void writeDataGoogleMaps(OutputStream out, int cellID, int lac) throws IOException { 
      DataOutputStream dataOutputStream = new DataOutputStream(out); 
      dataOutputStream.writeShort(21); 
      dataOutputStream.writeLong(0); 
      dataOutputStream.writeUTF("en"); 
      dataOutputStream.writeUTF("Android"); 
      dataOutputStream.writeUTF("1.0"); 
      dataOutputStream.writeUTF("Web"); 
      dataOutputStream.writeByte(27); 
      dataOutputStream.writeInt(0); 
      dataOutputStream.writeInt(0); 
      dataOutputStream.writeInt(3); 
      dataOutputStream.writeUTF(""); 

      dataOutputStream.writeInt(cellID); 
      dataOutputStream.writeInt(lac); 

      dataOutputStream.writeInt(0); 
      dataOutputStream.writeInt(0); 
      dataOutputStream.writeInt(0); 
      dataOutputStream.writeInt(0); 
      dataOutputStream.flush(); 
   } 

} 
Nate
  • 31,017
  • 13
  • 83
  • 207
  • 1
    ,Thanks alot. Your answer is very comprehensive and useful. Before I make any changes in my code can you please explain the following: – Sarah Aug 15 '12 at 05:10
  • ,1) You say "There is no reason to keep looping, asking if the location is not equal to {0.0, 0.0}. That's inefficient. With my code, you will just get notified when the location does change." Does this mean that I do not have to implement the Loading Screen dialog of "Refresh Location". The location is anyways updated for any changes if I call the GPSHandler.getInstance().setListener(this) in the constructor?Your code wipes out the use of the "refresh" button since location is automatically updated. Is that correct? – Sarah Aug 15 '12 at 05:10
  • 2) I believe I had not very well understood the GPSHandler class. If a handset (BB) supports GPS but is not currently available (inside a building etc), location is fetched /determined from the nearest cell tower the mobile is connected to. Why should this include fetching the location from google webservice which would only work if internet connection is available. Otherwise, location will not be acquired inside with no GPS available. Please correct me if my observation is wrong. – Sarah Aug 15 '12 at 05:11
  • @Sarah, regarding question (1): first, you need to decide how you **want** your UI to work. Do you want users to push a button, to get the current location, or do you want the app to always be monitoring for location changes? There is no right answer to this question. Let me know what you prefer, and I'll update my answer. – Nate Aug 15 '12 at 05:27
  • @Sarah, regarding question (2): the only thing I changed in the logic from your original `handleeGPS` class was that I switched the boolean condition in the `if` statement. In your original code, you check if BB Maps are installed. If so, then you asked the Google web service for the location. If BB Maps are not installed, you first tried to get the location from the device, and if that didn't work, you used the exact same code to ask the Google web service for the location. All I changed was to switch the if statement (what's done for BB Maps installed, with what is done if not installed) – Nate Aug 15 '12 at 05:32
  • regarding question (1) I believe it would be useful if the app always monitors the location changes and updates the location automatically informing the user through a Dialog that the location has been updated. – Sarah Aug 15 '12 at 05:37
  • regarding question (2) I do understand that you only worked around the handleeGPS class without changing the logic. However, due to my lack of understanding, I was believing that the if GPS is not available (supported but not available) the location is updated via cell tower and not the Google web service. Since Google web service requires internet connection, I would not want to implement this. It would be useful if the location is updated automatically and GPS location is always given a preference over Cell Tower.Can you please help me on this? – Sarah Aug 15 '12 at 05:41
  • I would like to acquire the location as follows: 1) Check if GPS is available -> Get Location from GPS 2) Else Check if internet is available -> Get Location from Google Webservice 3) Else Get Location from mobile network cell tower – Sarah Aug 15 '12 at 05:57
  • @Sarah, ok, so we can do that, but now you're talking about something different from what your original code was attempting to do. Here's what I did: I just updated my answer above, to show how your button click handler (`fieldChanged()`) should look, **if you keep a location refresh button**. I updated the `GPSHandler` class to let you start, or restart location updates with the `startLocationUpdates()` method. I would then recommend that you try to implement my code, and then post a **new** question on stack overflow, using the last 3 comments you posted. Thanks! – Nate Aug 15 '12 at 07:55
  • @Sarah, sorry the method above was `requestLocationUpdates()`, not `startLocationUpdates()`. – Nate Aug 15 '12 at 08:08
  • thank you very much. your post has indeed been very useful and informative. Many of my concepts have been cleared. The difference between the updated and the older GPSHandler is the fact that earlier location was updated/refreshed automatically and now it is updated only through the "refresh button". Is that right?I will stick to the older code of automatically refreshing/acquiring the new location. I am doing this by calling the GPSHandler.getInstance().setListener(this) in the constructor. Please confirm. – Sarah Aug 15 '12 at 08:17
  • @Sarah, unfortunately, no. My original `GPSHandler` code, and your original `handleeGPS` class, have the same basic location fix logic. Both of them just try to get a location when the internal GPS thread is started, and that's the end of it. It's certainly possible to use BlackBerry location services to continually update our code, whenever your location changes, but that would involve more significant changes. That's why I suggested posting a new question, with your 3 comments from 2 hours ago as the **requirements** for the new solution. Hope that's more clear. – Nate Aug 15 '12 at 08:24
  • yes that clears it all. thanks. I get an error implementing GPSHandler.getInstance().setListener(this); in the field listener. I have implemented the code of the listener in a method instead refreshCoordinates() and call that method from this listener. – Sarah Aug 15 '12 at 08:26
  • @Sarah, are you getting a **compile error**? If so, did you remember to make your class declare that it `implements GPSListener`. – Nate Aug 15 '12 at 08:35
  • Yes I have declared implements GPSListener. If I call GPSHandler.getInstance().setListener(this); in the fieldListener, it gives an error "The method setListener(setListener) in the type GPSHandler is not applicable for the arguments (new FieldChangeListener) – Sarah Aug 15 '12 at 08:44
  • @Sarah, ah, yes. You can't call `setListener(this)` **inside** the anonymous `FieldChangeListener` class. It is the parent class that would be the `GPSListener`. So, in the code, right before your `FieldChangeListener`, you should declare a variable like this: `final GPSListener listener = this;`. Then, from **inside** the `fieldChanged()` method, you can call `GPSHandler.getInstance().setListener(listener);`. – Nate Aug 17 '12 at 01:52
  • @Sarah, actually, an easier way would probably be to call `GPSHandler.getInstance().setListener(this);` **before** you assign your `FieldChangeListener` object. – Nate Aug 17 '12 at 01:56
2

There's a lot of code that we can't see (e.g. getLatitude(), getLongitude(), refreshDetails()). So, there could be something going wrong there. Also, I don't see any Loading Screen in the code you posted, so I can't say why that isn't showing.

But, here's something that doesn't look right:

        synchronized (Application.getEventLock())
        {
            busyDialog.show();
        }

If you read this BlackBerry forum question, you'll see that trying to synchronize on the application event lock from the main (UI) thread can cause your app to freeze. The public void fieldChanged(Field field, int context) method is always called on the UI thread, because it's the UI thread that monitors buttons for clicks, and calls back your click handlers, like fieldChanged().

You can also read the BlackBerry API docs for Application, that explain that getEventLock() is for worker (also known as background) threads, not the main (aka UI) thread.

So, there's no need to use special techniques to get the event lock, in code that already runs on the UI thread. Instead of the code above, just do this:

            busyDialog.show();

Both of these techniques:

        synchronized (Application.getEventLock())
        {
            busyDialog.show();
        }

or

        UiApplication.getUiApplication().invokeLater(new Runnable() {
            public void run() {
               busyDialog.show();  
            }
        });

are ways to safely call UI methods from a background thread. But, you shouldn't use those in code that you know is running on the UI thread already.

Try fixing that, and see if your problem disappears.

Edit: also, your code is checking for a username and password before refreshing the location. Is that really what you want? I don't think this has anything to do with your problem, but normally, I wouldn't expect to need a username or password to access location services. Of course, I don't know your application, so this is really just a comment on my part.

Nate
  • 31,017
  • 13
  • 83
  • 207
  • Hi Nate, I tried the code without the eventLock and it now throws an IllegalStateException. I have removed the username,password as it was just an extra line of code that I included by mistake. My refresh button is : Thread backgroundWorker = new Thread(new Runnable() { public void run() { refreshCoordinates(); } }); backgroundWorker.start(); – Sarah Aug 14 '12 at 09:08
  • and the method called: do { busyDialog.setEscapeEnabled(false); busyDialog.show(); getLatitude(handleeGPS.latitude); getLongitude(handleeGPS.longitude); String lg = longi; String lt = lati; }while((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0)); UiApplication.getUiApplication().invokeLater( new Runnable() { public void run () { lblLatitude.setText(lati); lblLongitude.setText(longi); } – Sarah Aug 14 '12 at 09:09
  • @Sarah, first a suggestion. If you make changes to your code, can you **edit** your question above, and put the new code at the bottom, with some text that says **"Edit:"** or **"Update:"**? That makes it a lot easier to read code, than if it's pasted into a comment. Thanks. – Nate Aug 14 '12 at 09:52
  • @Sarah, like I said, it's hard to read code posted into a comment. But, it looks like your second comment above has **changed** the `refreshCoordinates()` method, which I did not suggest doing anything to. It looks like you added `busyDialog.setEscapeEnabled(false); busyDialog.show();` to that method. But, `refreshCoordinates()` runs in the background, so you are not allowed to make UI calls from there. Anything with the `busyDialog` is a UI call. – Nate Aug 14 '12 at 09:54
  • @Sarah, I also noticed that in your original code that the place where you create `busyDialog` is actually commented out. So, that code can't even compile. Please post for us **exactly** the code that you're using. Again, `busyDialog` is a UI class, so you should be manipulating it on the UI thread. That means, using it inside `fieldChanged()` is safe, but inside `refreshCoordinates()`, you must wrap calls to `busyDialog` with `getUiApplication().invokeLater()`. Does that make sense? – Nate Aug 14 '12 at 09:56
  • I have now edited the post with the updated code. This brings up the "Loading screen" but disappears even before one could see it. The screen disappears before the coordinates change from 0.0 , 0.0. I have included the two methods above with which we acquire the latitude and longitude values. The values are passed from the handleeGPS class to these methods. – Sarah Aug 14 '12 at 10:22
  • @Sarah, again, you don't show us anything about a "Loading Screen", so we can't help you debug anything with that. Thank you for posting your `getLatitude()` and `getLongitude()` methods. It turns out those are quite important. I had (incorrectly) assumed that `getLatitude()` was making some call to location services to request the location, but it's not. It only calls `Double.toString()`. This is not good for two reasons: (1) we still can't see how you are actually trying to get the location, so we can't help figure out how it changes from {0,0}, and (2) this call is going to burn CPU. – Nate Aug 14 '12 at 10:29
  • @Sarah, elaborating on my previous comment, you have a `while` loop that constantly checks the value of your `lati` and `longi` strings, with no delay at all between loop iterations. This is going to drive CPU usage to 100%, which is never good. I had thought that maybe `getLatitude()` was making a request to update the location, and then just waiting for a response, which would not necessarily spike CPU usage. Anyway, to help you, we need to see how you're updating the latitude and longitude. But, I'm sure that `while` loop will need changing. – Nate Aug 14 '12 at 10:33
  • the loading screen is Dialog busyDialog = new Dialog("Refreshing Location...", null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS)); that is called outside the methods and listeners. I am updating the location by calling the handleGPS class. This class returns the latitude and longitude which are passed as double values in the getLatitude and getLongitude methods. Yes the purpose is to update the location and for that it calls the class, if the returned value is 0.0 then it calls it again. I have added the handleeGPS class in the edit. – Sarah Aug 14 '12 at 10:35
2

I think thee is simple answer is error here:

((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));

You have to use String.equals() instead of == operator.

After first call longi and lati have "0.0" value. But == will return false because it compare references by default and they are different because it's different objects.

Eugen Martynov
  • 19,888
  • 10
  • 61
  • 114
  • I completely agree that using `==` is the wrong way to test strings. It seems like this problem has come up so many times here recently! However, it is still possible for that test to work right **sometimes**, and it might be working right here. I don't write compilers, but if I had to guess what's happening, the compiler tries to optimize by finding all the `String` literals in your code. If there's two places that have `"0.0"`, it tries not to create two different `String` objects. So, the `longi` variable is set to a `String` that is `"0.0"`, and the if test compares against the same. – Nate Aug 15 '12 at 01:18
  • By the way, I did go ahead and build a program to test this (on a 9550 simulator), and verify that **yes**, it is possible for the `==` to work the way the author wants it to. So, I think there's other problems in her code. But, in general, you're right, and `==` is not the right way to test strings. – Nate Aug 15 '12 at 01:20
  • Just small comment. It's not compiler optimisation but runtime. I don't think compiler is so smart to know that after first call two double values are zero. – Eugen Martynov Aug 15 '12 at 05:29
  • There's no `double` values involved, right? She doesn't show this code, so we can only guess, but I would guess that she initializes the member variable `longi` like this: `private String longi = "0.0";`. Then, she checks `if (longi == "0.0")`. What I'm suggesting is that the compiler *may* lay out a string object to represent that literal value, like if there was a named object `private String ZERO = "0.0";` If it used that string object in both places where the literal "0.0" is coded, then that could cause `==` to return true. That information is easily available at compile time, right? – Nate Aug 15 '12 at 08:01
  • That's right that we don't see initialization. But it doesn't matter. Before comparing there is call of `getLatitude` and `getLongitude` and it will assign `Double.toString` for the values. @Nate I have nothing against you. You gave correct answer and I just put small remark. – Eugen Martynov Aug 15 '12 at 08:41
  • yes, you're 100% right. I missed that. Even if `longi` is initialized to `"0.0"`, it must have been set to another value at least once before the `if` statement. Good catch! Thanks, @Eugen. – Nate Aug 17 '12 at 01:48
  • @Nate What you see the compiler doing is 'interning' which is required by the language spec for string literals in any Java program. You can also take a string constructed at runtime, and get similar reference equality by calling the 'intern()' method, and then using the returned string. There is a giant table of strings that have been interned, and the intern() function does a lookup to find an existing canonical reference. – Michael Donohue Aug 26 '12 at 20:53
  • @MichaelDonohue, great explanation. Thanks! And to Eugen, too! – Nate Aug 26 '12 at 21:44