BlackBerry Обновить местоположение через GPS или Cell Tower
Я пытаюсь обновить текущее местоположение одним нажатием кнопки. Местоположение может быть получено через GPS или Cell Tower, в зависимости от того, что доступно. Моя проблема в том, что я никогда не вижу "Экран загрузки". Я знаю, что это происходит, когда что-то появляется / закрывается мгновенно, а координаты остаются нулевыми. Может ли кто-нибудь мне помочь - что я делаю не так внизу?
Ни местоположение не обновляется, ни экран загрузки не появляется. Без экрана загрузки и несколькими нажатиями кнопки "Обновить" я получаю местоположение. Ниже приведен мой код для обработки нажатий на кнопку "Обновить":
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();
}
}
3 ответа
Итак, хотя мой первоначальный ответ был действительным, у нового кода, который вы опубликовали, есть некоторые другие проблемы, поэтому я публикую второй ответ. Было достаточно вещей, которые выглядели не так, что я просто переписал handleeGPS
учебный класс. Я объясню основные изменения, которые я сделал, один за другим:
Попробуйте использовать соглашения об именах Java. Это помогает нам помочь вам. Перед тем, как вы разместили код в своем
handleeGPS
класс, я думал, что это переменная, потому что строчные имена обычно используются для переменных, а не классов.Избегайте дублирования кода.
handleeGPS
У класса было много кода для чтения, но в основном это был код для определения местоположения через веб-сервис Google, который вы дублировали в двух местах. Просто создайте метод, который содержит только этот код, и вызовите его дважды.Я переименовал ваш
handleeGPS
класс дляGPSHandler
, Я не уверен, еслиhandlee
была ошибка, или если это слово на другом языке, который вы использовали. В любом случае имя должно начинаться с заглавной буквы.Избегайте много
static
переменные и методы. Иногда действительно должно быть только одно из чего-то. Класс обработки GPS, вероятно, является хорошим примером этого, потому что устройство имеет только одну систему GPS. Но, чтобы обеспечить выполнение этой конструкции кода, не помечайте все какstatic
, Просто сделайте класс Singleton, который включает в себя создание только одногоstatic
переменная-член (_instance
) и один статический метод (getInstance()
). В моем коде вы получите доступ к классу следующим образом:GPSHandler gps = GPSHandler.getInstance();
,Я считаю, что проверка, была ли у вас установлена карта BB, на самом деле была обратной. Вы посмотрели вверх
net_rim_bb_lbs
модуля, и если он был больше нуля (что означает, что BB Maps установлен), то вы обратились непосредственно к веб-сервису Google. Я думаю, что вы хотите наоборот (попробуйте устройство GPS, если установлены BB Maps). Кроме того, начиная с 6.0, вы должны проверитьnet_rim_bb_maps
, тоже.Прежде чем вы разместили обновление, я думал, что ваш
getLatitude()
а такжеgetLongitude()
методы фактически выбирали местоположение устройства. Это было плохое предположение с моей стороны. Они просто конвертировали числа в строки. Таким образом, нет никаких причин для этого в фоновом режиме (сThread
). Вы уже написали свойhandleeGPS
класс, чтобы использовать фоновый поток, что хорошо. Одной фоновой нити достаточно. Пользовательский интерфейс, который использует информацию о местоположении, также не должен иметь фонаThread
, Я изменил код, чтобы добавитьGPSListener
интерфейс. Этот интерфейс должен быть реализован вашим кодом пользовательского интерфейса, чтобы получать обновления местоположения. Нет причин продолжать цикл, спрашивая, не совпадает ли местоположение с {0.0, 0.0}. Это неэффективно. С моим кодом вы просто получите уведомление, когда местоположение действительно изменится.Оригинальный код не был потокобезопасным.
handleeGPS
latitude
а такжеlongitude
переменные были установлены в фоновом потоке и доступны в потоке пользовательского интерфейса. Это не безопасно. Два потока не должны одновременно считывать и записывать один и тот же фрагмент данных. Изменяя код, чтобы передать данные о местоположении вGPSListener
Это позволяет избежать этой проблемы.Я раскомментировал
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();
}
}
Там много кода, который мы не можем увидеть (например, 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();
}
или же
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
busyDialog.show();
}
});
способы безопасного вызова методов пользовательского интерфейса из фонового потока. Но вы не должны использовать те в коде, который, как вы знаете, уже выполняется в потоке пользовательского интерфейса.
Попробуйте исправить это и посмотрите, исчезнет ли ваша проблема.
Редактировать: также, ваш код проверяет имя пользователя и пароль перед обновлением местоположения. Это действительно то, что вы хотите? Я не думаю, что это как-то связано с вашей проблемой, но обычно я не ожидаю, что для доступа к службам определения местоположения потребуется имя пользователя или пароль. Конечно, я не знаю вашу заявку, так что это на самом деле просто комментарий с моей стороны.
Я думаю, что ты простой ответ, здесь ошибка:
((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));
Вы должны использовать String.equals()
вместо ==
оператор.
После первого звонка longi
а также lati
иметь "0.0"
значение. Но ==
вернусь false
потому что он сравнивает ссылки по умолчанию, и они разные, потому что это разные объекты.