我正试图通过点击按钮刷新当前位置。可以通过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();
}
}
答案 0 :(得分:5)
好的,所以虽然我的原始答案是有效的,但您发布的新代码有一些不同的问题,所以我发布了第二个答案。有足够的事情看起来不对,我刚刚重写了你的handleeGPS
课程。我将逐一解释我所做的重大改变:
尝试使用Java naming conventions。这使我们更容易为您提供帮助。在将代码发布到handleeGPS
类之前,我认为它是一个变量,因为小写名称通常用于变量,而不是类。
避免重复代码。 handleeGPS
课程有很多代码可供阅读,但大部分都是从Google的网络服务获取位置的代码,您可以在两个地方复制这些代码。只需创建一个只包含该代码的方法,然后调用它两次。
我将您的handleeGPS
课程重命名为GPSHandler
。我不确定handlee
是否是错误,或者是否是您使用的其他语言的单词。无论如何,名称至少应以大写字母开头。
避免使用大量static
变量和方法。有时,确实应该只有一个东西。 GPS处理类可能就是一个很好的例子,因为该设备只有一个GPS系统。但是,要强制执行此代码构造,请不要将所有内容标记为static
。仅make the class a Singleton,其中只涉及创建一个static
成员变量(_instance
)和一个静态方法(getInstance()
)。在我的代码中,您将访问类:GPSHandler gps = GPSHandler.getInstance();
。
我相信你对是否安装了BB地图的检查实际上是倒退了。您查找了net_rim_bb_lbs
模块,如果它大于零(这意味着安装了BB地图),那么您就直接访问了Google网络服务。我认为你想要反过来(如果安装了BB地图,请尝试设备GPS)。此外,自6.0起,您还需要检查net_rim_bb_maps
。
在您发布更新之前,我认为您的getLatitude()
和getLongitude()
方法实际上是在获取设备位置。这对我来说是一个糟糕的假设。他们只是将数字转换为字符串。所以,没有理由在后台完成(使用Thread
)。您已经编写了handleeGPS
类来使用后台线程,这很好。一个后台线程就足够了。使用位置信息的用户界面不应该还需要背景Thread
。我更改了代码以添加GPSListener
接口。该接口应由您的UI代码实现,以接收位置更新。没有理由继续循环,询问位置是否不等于{0.0,0.0}。那效率很低。使用我的代码,您只需在位置发生变化时收到通知。
原始代码不是线程安全的。 handleeGPS
latitude
和longitude
变量在后台线程上设置,并在UI线程上访问。那不安全。两个线程不应该同时读取和写入同一条数据。通过更改代码以将位置数据推送到GPSListener
,可以避免此问题。
我取消注释了Dialog.alert()
课程中的handleeGPS
代码,这对您没有用,因为您不允许从后台进行UI调用。我用UiApplication.getUiApplication().invokeLater()
包围了这些电话,以确保它们安全。
要在您的UI代码中使用此类,您可以执行此操作,而不是使用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();
}
}
答案 1 :(得分:2)
我们看不到很多代码(例如getLatitude()
,getLongitude()
,refreshDetails()
)。所以,那里可能会出现问题。此外,我在您发布的代码中看不到任何加载屏幕,所以我不能说为什么没有显示。
但是,这看起来不对劲:
synchronized (Application.getEventLock())
{
busyDialog.show();
}
If you read this BlackBerry forum question,您会看到尝试同步应用事件锁来自主(UI)线程会导致您的应用冻结。始终在UI线程上调用public void fieldChanged(Field field, int context)
方法,因为它是监视点击按钮的UI线程,并回调您的点击处理程序,如fieldChanged()
。
您还可以阅读the BlackBerry API docs for Application,其中说明getEventLock()
适用于 worker (也称为后台)主题,而不是主要内容(又名 UI )线程。
因此,在已经在UI线程上运行的代码中,不需要使用特殊技术来获取事件锁定。而不是上面的代码,只需这样做:
busyDialog.show();
这两种技术都是:
synchronized (Application.getEventLock())
{
busyDialog.show();
}
或
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
busyDialog.show();
}
});
是安全从后台主题调用UI方法的方法。但是,您不应该在已经在UI线程上运行的代码中使用它们。
尝试修复它,看看问题是否消失。
编辑,在刷新位置之前,您的代码正在检查用户名和密码。这真的是你想要的吗?我不认为这与您的问题有任何关系,但通常情况下,我不希望需要用户名或密码来访问位置服务。当然,我不知道你的申请,所以这只是我的评论。
答案 2 :(得分:2)
我认为你的答案很简单就是错误:
((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));
您必须使用String.equals()
代替==
运营商。
首次通话后longi
和lati
有"0.0"
值。但是==
会返回false
,因为默认情况下它会比较引用,但它们是不同的,因为它是不同的对象。