Местоположение BlackBerry Refresh через GPS или сотовую вышку

Я пытаюсь обновить текущее местоположение одним нажатием кнопки. Местоположение можно получить с помощью GPS или сотовой вышки, в зависимости от того, что доступно. Моя проблема в том, что я никогда не вижу «Экран загрузки». Я знаю, что это появляется, когда что-то появляется/закрывается мгновенно, в то время как координаты остаются нулевыми. Может кто-нибудь помочь мне - что я делаю неправильно ниже?

Ни местоположение не обновляется, ни появляется экран загрузки. Без экрана загрузки и многократным нажатием кнопки «обновить» я получаю местоположение. Ниже приведен мой код для обработки кликов по кнопке «Обновить»:

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();
    }
};

И мой метод refreshCoordinates() выглядит следующим образом:

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;
}

Класс, который возвращает значения широты и долготы:

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();
    }
}

person Sarah    schedule 14.08.2012    source источник
comment
спасибо за публикацию обновления. Я вижу пару проблем с классом handleeGPS, но мне уже поздно, и мне нужно спать. если кто-то еще не поможет вам с этим сегодня, я напишу больше завтра.   -  person Nate    schedule 14.08.2012
comment
@Нейт, хорошо, спасибо. Я тоже буду работать вокруг себя. Буду ждать ваших отзывов завтра.   -  person Sarah    schedule 14.08.2012


Ответы (3)


Итак, хотя мой первоначальный ответ был верным, опубликованный вами новый код имеет некоторые другие проблемы, поэтому я публикую второй ответ. Было достаточно вещей, которые выглядели неправильно, поэтому я просто переписал ваш handleeGPS класс. Я объясню основные изменения, которые я сделал, одно за другим:

  1. Попробуйте использовать соглашения об именах Java. Так нам будет проще вам помочь. Прежде чем вы отправили код в свой класс handleeGPS, я думал, что это переменная, потому что имена в нижнем регистре обычно используются для переменных, а не для классов.

  2. Избегайте дублирования кода. В классе handleeGPS было много кода, который нужно было прочитать, но большая его часть была кодом для получения местоположения из веб-службы Google, который вы продублировали в двух местах. Просто создайте метод, содержащий только этот код, и вызовите его дважды.

  3. Я переименовал ваш класс handleeGPS в GPSHandler. Я не уверен, было ли handlee ошибкой или это слово на другом языке, которое вы использовали. В любом случае, имя должно начинаться как минимум с заглавной буквы.

  4. Избегайте множества static переменных и методов. Иногда действительно должен быть только один из чего-то. Класс обработки GPS, вероятно, является хорошим примером этого, потому что устройство имеет только одну систему GPS. Но чтобы обеспечить соблюдение этой конструкции кода, не помечайте все как static. Просто сделайте класс Singleton, что предполагает создание только одного static переменная-член (_instance) и один статический метод (getInstance()). В моем коде вы получите доступ к классу следующим образом: GPSHandler gps = GPSHandler.getInstance();.

  5. Я полагаю, что проверка того, были ли установлены карты BB, на самом деле была задом наперед. Вы просматривали модуль net_rim_bb_lbs, и если он был больше нуля (что означает, что BB Maps установлены), то вы обращались непосредственно к веб-сервису Google. Я думаю, вы хотите, чтобы было наоборот (попробуйте устройство GPS, если установлены карты BB). Кроме того, начиная с 6.0, вам также необходимо проверять наличие net_rim_bb_maps.

  6. Прежде чем вы опубликовали обновление, я думал, что ваши методы getLatitude() и getLongitude() на самом деле получают местоположение устройства. Это было плохим предположением с моей стороны. Они просто преобразовывали числа в строки. Таким образом, нет причин делать это в фоновом режиме (с Thread). Вы уже написали свой класс handleeGPS для использования фонового потока, и это хорошо. Достаточно одного фонового потока. Пользовательский интерфейс, использующий информацию о местоположении, также не должен нуждаться в фоне Thread. Я изменил код, чтобы добавить интерфейс GPSListener. Этот интерфейс должен быть реализован вашим кодом пользовательского интерфейса, чтобы получать обновления местоположения. Нет причин продолжать зацикливаться, спрашивая, не равно ли местоположение {0.0, 0.0}. Это неэффективно. С моим кодом вы просто получите уведомление, когда местоположение действительно изменится.

  7. Исходный код не был потокобезопасным. Переменные handleeGPS latitude и longitude были установлены в фоновом потоке и доступны в потоке пользовательского интерфейса. Это не безопасно. Два потока не должны одновременно читать и записывать один и тот же фрагмент данных. Изменив код для отправки данных о местоположении в GPSListener, можно избежать этой проблемы.

  8. Я раскомментировал код Dialog.alert(), который у вас был внутри вашего класса handleeGPS, который не сработал бы для вас, потому что вам не разрешено выполнять вызовы пользовательского интерфейса из фона. Я окружил эти звонки UiApplication.getUiApplication().invokeLater(), чтобы сделать их безопасными.

Чтобы использовать этот класс где-то в коде вашего пользовательского интерфейса, вы должны сделать это вместо использования Thread для запуска вашего метода refreshCoordinates():

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();               
}     

Убедитесь, что класс, в который вы поместили этот код (выше), также implements GPSListener, который является интерфейсом, определенным здесь:

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

и, наконец, 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(); 
   } 

} 
person Nate    schedule 15.08.2012
comment
,Большое спасибо. Ваш ответ очень исчерпывающий и полезный. Прежде чем я внесу какие-либо изменения в свой код, не могли бы вы объяснить следующее: - person Sarah; 15.08.2012
comment
,1) Вы говорите, что нет причин продолжать зацикливаться, спрашивая, не равно ли местоположение {0.0, 0.0}. Это неэффективно. С моим кодом вы просто получите уведомление, когда местоположение действительно изменится. Означает ли это, что мне не нужно реализовывать диалоговое окно «Экран загрузки» для «Обновить местоположение». Местоположение в любом случае обновляется для любых изменений, если я вызываю GPSHandler.getInstance().setListener(this) в конструкторе? Ваш код стирает использование кнопки обновления, поскольку местоположение обновляется автоматически. Это правильно? - person Sarah; 15.08.2012
comment
2) Я полагаю, что не очень хорошо понял класс GPSHandler. Если трубка (BB) поддерживает GPS, но в данный момент недоступна (внутри здания и т. д.), местоположение извлекается/определяется с ближайшей вышки сотовой связи, к которой подключен мобильный телефон. Почему это должно включать получение местоположения из веб-службы Google, которое будет работать только при наличии подключения к Интернету. В противном случае местоположение не будет получено внутри без GPS. Пожалуйста, поправьте меня, если мое наблюдение неверно. - person Sarah; 15.08.2012
comment
@Sarah, что касается вопроса (1): во-первых, вам нужно решить, как вы хотите работать с вашим пользовательским интерфейсом. Вы хотите, чтобы пользователи нажимали кнопку, чтобы получить текущее местоположение, или вы хотите, чтобы приложение всегда отслеживало изменения местоположения? На этот вопрос нет правильного ответа. Дайте мне знать, что вы предпочитаете, и я обновлю свой ответ. - person Nate; 15.08.2012
comment
@Sarah, что касается вопроса (2): единственное, что я изменил в логике вашего исходного класса handleeGPS, это то, что я переключил логическое условие в операторе if. В исходном коде вы проверяете, установлены ли карты BB. Если да, то вы запросили местоположение у веб-службы Google. Если BB Maps не установлены, вы сначала пытались получить местоположение с устройства, и если это не сработало, вы использовали тот же код, чтобы запросить местоположение в веб-службе Google. Все, что я изменил, это переключить оператор if (что делается для установленных BB Maps, что делается, если они не установлены) - person Nate; 15.08.2012
comment
относительно вопроса (1) Я считаю, что было бы полезно, если бы приложение всегда отслеживало изменения местоположения и обновляло местоположение, автоматически информируя пользователя через диалоговое окно о том, что местоположение было обновлено. - person Sarah; 15.08.2012
comment
относительно вопроса (2) я понимаю, что вы работали только с классом handleeGPS без изменения логики. Однако из-за моего непонимания я полагал, что если GPS недоступен (поддерживается, но недоступен), местоположение обновляется через вышку сотовой связи, а не через веб-службу Google. Поскольку веб-служба Google требует подключения к Интернету, я бы не хотел это реализовывать. Было бы полезно, если бы местоположение обновлялось автоматически, а местоположению GPS всегда отдавалось предпочтение перед вышкой сотовой связи. Не могли бы вы помочь мне в этом? - person Sarah; 15.08.2012
comment
Я хотел бы получить местоположение следующим образом: 1) Проверить, доступен ли GPS -> Получить местоположение из GPS 2) В противном случае Проверить, доступен ли Интернет -> Получить местоположение из веб-службы Google 3) В противном случае Получить местоположение от вышки мобильной сети - person Sarah; 15.08.2012
comment
@ Сара, хорошо, так что мы можем это сделать, но теперь вы говорите о чем-то отличном от того, что пытался сделать ваш исходный код. Вот что я сделал: я только что обновил свой ответ выше, чтобы показать, как должен выглядеть обработчик нажатия кнопки (fieldChanged()), если вы сохраните кнопку обновления местоположения. Я обновил класс GPSHandler, чтобы вы могли начать или перезапустить обновления местоположения с помощью метода startLocationUpdates(). Затем я бы порекомендовал вам попробовать реализовать мой код, а затем опубликовать новый вопрос о переполнении стека, используя последние 3 опубликованных вами комментария. Спасибо! - person Nate; 15.08.2012
comment
@ Сара, извините, метод выше был requestLocationUpdates(), а не startLocationUpdates(). - person Nate; 15.08.2012
comment
большое спасибо. Ваш пост действительно был очень полезным и информативным. Многие из моих концепций были очищены. Отличие обновленного GPSHandler от старого заключается в том, что раньше местоположение обновлялось/обновлялось автоматически, а теперь обновляется только через кнопку обновления. Верно ли это? Я буду придерживаться старого кода автоматического обновления/получения нового местоположения. Я делаю это, вызывая GPSHandler.getInstance().setListener(this) в конструкторе. Пожалуйста подтвердите. - person Sarah; 15.08.2012
comment
@ Сара, к сожалению, нет. Мой исходный код GPSHandler и ваш исходный класс handleeGPS имеют одинаковую базовую логику определения местоположения. Оба они просто пытаются получить местоположение, когда запускается внутренний поток GPS, и на этом все заканчивается. Конечно, можно использовать службы определения местоположения BlackBerry для постоянного обновления нашего кода всякий раз, когда меняется ваше местоположение, но это потребует более значительных изменений. Вот почему я предложил опубликовать новый вопрос с вашими 3 комментариями, сделанными 2 часа назад, в качестве требований для нового решения. Надеюсь, это более понятно. - person Nate; 15.08.2012
comment
да это все проясняет. благодаря. Я получаю сообщение об ошибке при реализации GPSHandler.getInstance().setListener(this); в полевом слушателе. Я реализовал код слушателя в методе вместо refreshCoordinates() и вызываю этот метод из этого слушателя. - person Sarah; 15.08.2012
comment
@Sarah, вы получаете ошибку компиляции? Если да, то не забыли ли вы объявить свой класс, что он implements GPSListener. - person Nate; 15.08.2012
comment
Да, я объявил, что реализует GPSListener. Если я вызову GPSHandler.getInstance().setListener(this); в fieldListener выдает ошибку Метод setListener(setListener) в типе GPSHandler неприменим для аргументов (новый FieldChangeListener) - person Sarah; 15.08.2012
comment
@ Сара, ах, да. Вы не можете вызывать setListener(this) внутри анонимного класса FieldChangeListener. Это родительский класс, который будет GPSListener. Итак, в коде, прямо перед вашим FieldChangeListener, вы должны объявить такую ​​переменную: final GPSListener listener = this;. Затем из внутри метода fieldChanged() можно вызвать GPSHandler.getInstance().setListener(listener);. - person Nate; 17.08.2012
comment
@Sarah, на самом деле, проще было бы вызвать GPSHandler.getInstance().setListener(this); перед назначением объекта FieldChangeListener. - person Nate; 17.08.2012

Есть много кода, который мы не видим (например, getLatitude(), getLongitude(), refreshDetails()). Так что там может быть что-то не так. Кроме того, я не вижу никакого экрана загрузки в опубликованном вами коде, поэтому я не могу сказать, почему он не отображается.

Но вот что-то не так:

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

Если вы читали этот вопрос на форуме BlackBerry, вы увидите, что попытка синхронизировать блокировку события приложения из основного (UI) потока может привести к зависанию вашего приложения. Метод public void fieldChanged(Field field, int context) всегда вызывается в потоке пользовательского интерфейса, поскольку именно поток пользовательского интерфейса отслеживает нажатия кнопок и вызывает обработчики кликов, например fieldChanged().

Вы также можете прочитать документы BlackBerry API для приложений, в которых объясняется, что getEventLock() предназначен для рабочих (также известных как фоновых) потоков, а не для основных (он же пользовательский интерфейс).

Таким образом, нет необходимости использовать специальные методы для получения блокировки событий в коде, который уже выполняется в потоке пользовательского интерфейса. Вместо приведенного выше кода просто сделайте следующее:

            busyDialog.show();

Обе эти техники:

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

or

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

способы безопасного вызова методов пользовательского интерфейса из фонового потока. Но вы не должны использовать их в коде, который, как вы знаете, уже работает в потоке пользовательского интерфейса.

Попробуйте исправить это и посмотрите, исчезнет ли ваша проблема.

Редактировать. Кроме того, ваш код проверяет имя пользователя и пароль перед обновлением местоположения. Это действительно то, чего вы хотите? Я не думаю, что это имеет какое-то отношение к вашей проблеме, но обычно я не ожидаю, что мне понадобится имя пользователя или пароль для доступа к службам определения местоположения. Конечно, я не знаю вашего приложения, так что это просто комментарий с моей стороны.

person Nate    schedule 14.08.2012
comment
Привет, Нейт, я попробовал код без eventLock, и теперь он выдает исключение IllegalStateException. Я удалил имя пользователя и пароль, так как это была просто дополнительная строка кода, которую я включил по ошибке. Моя кнопка обновления: Thread backgroundWorker = new Thread(new Runnable() {public void run() { refreshCoordinates(); } }); backgroundWorker.start(); - person Sarah; 14.08.2012
comment
и вызываемый метод: do { busyDialog.setEscapeEnabled(false); BusyDialog.show(); getLatitude (handleeGPS.широта); getLongitude(handleeGPS.longitude); Строка lg = лонги; Строка lt = лати; } 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); } - person Sarah; 14.08.2012
comment
@ Сара, сначала предложение. Если вы вносите изменения в свой код, можете ли вы отредактировать свой вопрос выше и поместить новый код внизу с текстом Изменить: или Обновить :? Это значительно упрощает чтение кода, чем если бы он был вставлен в комментарий. Спасибо. - person Nate; 14.08.2012
comment
@ Сара, как я уже сказал, трудно читать код, размещенный в комментарии. Но похоже, что ваш второй комментарий выше изменил метод refreshCoordinates(), с которым я ничего не предлагал делать. Похоже, вы добавили busyDialog.setEscapeEnabled(false); busyDialog.show(); к этому методу. Но refreshCoordinates() работает в фоновом режиме, поэтому вам не разрешено выполнять оттуда вызовы пользовательского интерфейса. Все, что связано с busyDialog, является вызовом пользовательского интерфейса. - person Nate; 14.08.2012
comment
@Sarah, я также заметил, что в вашем исходном коде место, где вы создаете busyDialog, фактически закомментировано. Таким образом, этот код даже не может быть скомпилирован. Опубликуйте для нас точный код, который вы используете. Опять же, busyDialog — это класс пользовательского интерфейса, поэтому вы должны манипулировать им в потоке пользовательского интерфейса. Это означает, что использовать его внутри fieldChanged() безопасно, но внутри refreshCoordinates() вы должны оборачивать вызовы busyDialog в getUiApplication().invokeLater(). Имеет ли это смысл? - person Nate; 14.08.2012
comment
Теперь я отредактировал сообщение с обновленным кодом. Это вызывает экран загрузки, но исчезает еще до того, как его можно было увидеть. Экран исчезает до того, как координаты изменятся с 0.0 на 0.0. Я включил два вышеуказанных метода, с помощью которых мы получаем значения широты и долготы. Значения передаются из класса handleeGPS в эти методы. - person Sarah; 14.08.2012
comment
@ Сара, опять же, ты ничего не показываешь нам об экране загрузки, поэтому мы не можем помочь тебе отладить что-либо с этим. Спасибо за публикацию ваших методов getLatitude() и getLongitude(). Оказывается, это очень важно. Я (ошибочно) предположил, что getLatitude() звонит в службу определения местоположения, чтобы запросить местоположение, но это не так. Он вызывает только Double.toString(). Это нехорошо по двум причинам: (1) мы все еще не можем видеть, как вы на самом деле пытаетесь получить местоположение, поэтому мы не можем помочь выяснить, как оно отличается от {0,0}, и (2) это call собирается сжечь процессор. - person Nate; 14.08.2012
comment
@Sarah, развивая мой предыдущий комментарий, у вас есть цикл while, который постоянно проверяет значение ваших строк lati и longi без каких-либо задержек между итерациями цикла. Это увеличит загрузку процессора до 100%, что никогда не бывает хорошо. Я думал, что, возможно, getLatitude() отправляет запрос на обновление местоположения, а затем просто ждет ответа, что не обязательно приведет к резкому увеличению загрузки ЦП. В любом случае, чтобы помочь вам, нам нужно посмотреть, как вы обновляете широту и долготу. Но я уверен, что цикл while нужно будет изменить. - person Nate; 14.08.2012
comment
экран загрузки: Dialog busyDialog = new Dialog(Refreshing Location..., null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS)); который вызывается вне методов и слушателей. Я обновляю местоположение, вызывая класс handleGPS. Этот класс возвращает широту и долготу, которые передаются как двойные значения в методах getLatitude и getLongitude. Да, цель состоит в том, чтобы обновить местоположение, и для этого он вызывает класс, если возвращаемое значение равно 0,0, он снова вызывает его. Я добавил класс handleeGPS в редактирование. - person Sarah; 14.08.2012

Я думаю, что здесь простой ответ - ошибка:

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

Вы должны использовать String.equals() вместо оператора ==.

После первого вызова longi и lati имеют значение "0.0". Но == вернет false, потому что он сравнивает ссылки по умолчанию, и они разные, потому что это разные объекты.

person Eugen Martynov    schedule 14.08.2012
comment
Я полностью согласен с тем, что использование == — неправильный способ проверки строк. Кажется, эта проблема поднималась здесь так много раз в последнее время! Тем не менее, этот тест все еще может работать правильно иногда, и он может работать прямо сейчас. Я не пишу компиляторы, но если бы мне нужно было угадать, что происходит, компилятор пытается оптимизировать, находя все String литералы в вашем коде. Если есть два места с "0.0", он пытается не создавать два разных объекта String. Таким образом, переменная longi установлена ​​на String, то есть "0.0", и проверка if сравнивается с ней. - person Nate; 15.08.2012
comment
Между прочим, я создал программу, чтобы протестировать это (на симуляторе 9550) и убедиться, что да, == может работать так, как хочет автор. Итак, я думаю, что в ее коде есть другие проблемы. Но в целом вы правы, и == не подходит для проверки строк. - person Nate; 15.08.2012
comment
Просто небольшой комментарий. Это не оптимизация компилятора, а среда выполнения. Я не думаю, что компилятор настолько умен, чтобы знать, что после первого вызова два двойных значения равны нулю. - person Eugen Martynov; 15.08.2012
comment
Там нет double значений, верно? Она не показывает этот код, поэтому мы можем только догадываться, но я предполагаю, что она инициализирует переменную-член longi следующим образом: private String longi = "0.0";. Затем она проверяет if (longi == "0.0"). Я предполагаю, что компилятор может разместить строковый объект для представления этого литерала, например, если был именованный объект private String ZERO = "0.0"; Если он использовал этот строковый объект в обоих местах, где литерал 0.0 закодировано, то это может привести к тому, что == вернет true. Эта информация легко доступна во время компиляции, верно? - person Nate; 15.08.2012
comment
Правильно, что мы не видим инициализацию. Но это не имеет значения. Перед сравнением происходит вызов getLatitude и getLongitude, и он назначит Double.toString для значений. @Нейт, я ничего против тебя не имею. Вы дали правильный ответ, а я просто сделал небольшое замечание. - person Eugen Martynov; 15.08.2012
comment
да, ты прав на 100%. Я пропустил это. Даже если longi инициализируется как "0.0", оно должно быть установлено в другое значение по крайней мере один раз перед оператором if. Хороший улов! Спасибо, @Eugen. - person Nate; 17.08.2012
comment
@Nate То, что вы видите, делает компилятор, это «интернирование», которое требуется спецификацией языка для строковых литералов в любой программе Java. Вы также можете взять строку, созданную во время выполнения, и получить аналогичное ссылочное равенство, вызвав метод «intern()», а затем используя возвращенную строку. Существует гигантская таблица интернированных строк, и функция intern() выполняет поиск существующей канонической ссылки. - person Michael Donohue; 27.08.2012
comment
@MichaelDonohue, отличное объяснение. Спасибо! И Евгению тоже! - person Nate; 27.08.2012