从非UI线程添加字段会在blackberry中引发异常?
大家好,我正在尝试一个例子,我有一个按钮,下载一个图像,然后它需要在屏幕上渲染。我使用下面的代码来完成它。我不知道我哪里出了问题。它向我抛出非法异常。任何人都可以看看我的代码,并为我提供一些帮助从非UI线程添加字段会在blackberry中引发异常?,blackberry,Blackberry,大家好,我正在尝试一个例子,我有一个按钮,下载一个图像,然后它需要在屏幕上渲染。我使用下面的代码来完成它。我不知道我哪里出了问题。它向我抛出非法异常。任何人都可以看看我的代码,并为我提供一些帮助 import java.io.IOException; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; import net.
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.container.MainScreen;
public class GoogleChart extends MainScreen implements FieldChangeListener{
ButtonField btn = new ButtonField("Download");
GoogleChart activeScreen = null;
public GoogleChart() {
setTitle("Download image");
btn.setChangeListener(this);
add(btn);
this.activeScreen = (GoogleChart)UiApplication.getUiApplication().getActiveScreen();
}
public void fieldChanged(Field field, int context) {
if(field == btn){
updateUI();
}
}
private void updateUI(){
synchronized (Application.getEventLock()) {
activeScreen.add(new BitmapField(downloadImage()));
activeScreen.invalidate();
}
}
public Bitmap downloadImage() {
byte[] dataArray;
InputStream input;
StringBuffer url = new StringBuffer("IMAGE URL");
HttpConnection httpConn = null;
Bitmap googleImage = null;
try {
httpConn = (HttpConnection) Connector.open(url.toString());
input = httpConn.openInputStream();
dataArray = net.rim.device.api.io.IOUtilities.streamToBytes(input);
googleImage = Bitmap.createBitmapFromBytes(dataArray, 0, -1, 1);
} catch (IOException e) {
e.printStackTrace();
}
return googleImage;
}
}
注意:图像下载可以正常工作。甚至我也用其他样品测试过
根据Dan的建议,我已经更改了以下代码,并将下载逻辑分离到另一个线程中
class Download extends Thread{
Bitmap googleImage = null;
private void updateUI(){
synchronized (Application.getEventLock()) {
if(googleImage != null){
activeScreen.add(new BitmapField(googleImage));
activeScreen.invalidate();
}
}
}
public void run() {
googleImage = downloadImage();
updateUI();
}
public Bitmap downloadImage() {
byte[] dataArray;
InputStream input;
StringBuffer url = new StringBuffer("http://");
HttpConnection httpConn = null;
Bitmap googleImage = null;
try {
httpConn = (HttpConnection) Connector.open(url.toString());
input = httpConn.openInputStream();
dataArray = net.rim.device.api.io.IOUtilities.streamToBytes(input);
googleImage = Bitmap.createBitmapFromBytes(dataArray, 0, -1, 1);
} catch (IOException e) {
e.printStackTrace();
}
return googleImage;
}
}
像这样调用线程
public void fieldChanged(Field field, int context) {
if(field == btn){
new Download().start();
}
}
您正在捕获事件锁并执行下载(锁定整个应用程序,直到完成)。
您需要使用线程执行UI线程的下载(不捕获事件锁),并在线程完成其任务后调用更新UI您正在捕获事件锁并执行下载(锁定整个应用程序直到完成)。
您需要使用一个线程来执行UI线程的下载(不捕获事件锁),并在线程完成任务后调用更新UI您到底得到了什么异常(它有任何消息吗?)?在哪一步/哪一行?如果您的
位图
太大,无法创建位图
实例,您可能会遇到非法异常。您的位图
有哪些维度(宽度x高度)?根据我的经验,从~1.5 Mpx开始,就不可能创建位图
(具体限制取决于设备型号/操作系统级别)
更新:
好的,那么为了弄清楚发生了什么,你可以尝试以下方法吗
private void updateUI() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
if (googleImage == null) {
Dialog.alert("googleImage is null");
} else {
Dialog.alert("googleImage is not null");
try {
BitmapField b = new BitmapField(googleImage);
Dialog.alert("BitmapField has been created OK");
activeScreen.add(b);
Dialog.alert("BitmapField has been added OK");
// no need to invalidate, since adding a new Field forces
// the screen to be repainted
} catch (Exception e) {
Dialog.alert("Got error: " + e);
}
}
}
});
}
你看到了什么消息?如果你得到“BitmapField已添加OK”,那么只需删除所有警报(只需在
catch
部分保留“仅限”以防出现),它应该可以正常工作。你到底得到了什么异常(它有任何消息吗?)?在哪一步/哪一行?如果您的位图
太大,无法创建位图
实例,您可能会遇到非法异常。您的位图
有哪些维度(宽度x高度)?根据我的经验,从~1.5 Mpx开始,就不可能创建位图
(具体限制取决于设备型号/操作系统级别)
更新:
好的,那么为了弄清楚发生了什么,你可以尝试以下方法吗
private void updateUI() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
if (googleImage == null) {
Dialog.alert("googleImage is null");
} else {
Dialog.alert("googleImage is not null");
try {
BitmapField b = new BitmapField(googleImage);
Dialog.alert("BitmapField has been created OK");
activeScreen.add(b);
Dialog.alert("BitmapField has been added OK");
// no need to invalidate, since adding a new Field forces
// the screen to be repainted
} catch (Exception e) {
Dialog.alert("Got error: " + e);
}
}
}
});
}
你看到了什么消息?如果你得到“BitmapField已添加OK”,那么只需删除所有警报(只需在“捕获”部分保留“仅限”以防出现),它应该可以正常工作。一些事情
1) 由于Download
是一个内部类,您不需要对activeScreen
的引用,因此,将updateUI
方法更改为以下内容:
private void updateUI() {
synchronized (Application.getEventLock()) {
if(googleImage != null ) {
add(new BitmapField(googleImage));
//invalidate();
}
}
ButtonField btn = new ButtonField("Download") {
protected boolean navigationClick(int arg0, int arg1) {
new Download().start();
return true;
}
};
2) FieldChangeListener不适用于我。如果您使用类似于new ButtonField(“blah”,ButtonField.CONSUME_CLICK”)的东西进行实例化,它可能会工作。但是,我正在使用以下内容来侦听单击:
private void updateUI() {
synchronized (Application.getEventLock()) {
if(googleImage != null ) {
add(new BitmapField(googleImage));
//invalidate();
}
}
ButtonField btn = new ButtonField("Download") {
protected boolean navigationClick(int arg0, int arg1) {
new Download().start();
return true;
}
};
3) 您正在下载哪种类型的图像?要处理JPG、PNG等。您需要这样的内容来处理字节数组,而不是位图
类上的静态方法:
EncodedImage img = EncodedImage.createEncodedImage(dataArray, 0, dataArray.length);
googleImage = img.getBitmap();
4) 在模拟器中,如果不使用MDS,则需要在URL后面加上;deviceside=true
对我有用。没有例外。在OS 5 9550模拟器上运行。一些事情
1) 由于Download
是一个内部类,您不需要对activeScreen
的引用,因此,将updateUI
方法更改为以下内容:
private void updateUI() {
synchronized (Application.getEventLock()) {
if(googleImage != null ) {
add(new BitmapField(googleImage));
//invalidate();
}
}
ButtonField btn = new ButtonField("Download") {
protected boolean navigationClick(int arg0, int arg1) {
new Download().start();
return true;
}
};
2) FieldChangeListener不为我工作。如果您使用类似于newbuttonfield(“blah”,ButtonField.CONSUME_CLICK)的东西进行实例化,
它可能会起作用。但是,我正在收听以下内容:
private void updateUI() {
synchronized (Application.getEventLock()) {
if(googleImage != null ) {
add(new BitmapField(googleImage));
//invalidate();
}
}
ButtonField btn = new ButtonField("Download") {
protected boolean navigationClick(int arg0, int arg1) {
new Download().start();
return true;
}
};
3) 您正在下载什么类型的图像?要处理JPG、PNG等,您需要这样的东西来处理字节数组,而不是Bitmap
类上的静态方法:
EncodedImage img = EncodedImage.createEncodedImage(dataArray, 0, dataArray.length);
googleImage = img.getBitmap();
4) 在模拟器中,如果不使用MDS,则需要在URL后面加上;deviceside=true
对我有用。没有例外。在OS 5 9550模拟器上运行。我使用了一个扩展线程的内部类,然后从fieldChanged()调用了run方法。这里的问题仍然是一样的。我希望它正在下载图像,但仍然存在在ui中更新的问题。我使用了一个扩展线程的内部类,然后从fieldChanged()调用了run方法。这里的问题仍然是一样的。我希望它正在下载图像,但我仍然有在ui中更新的问题。异常不是由于图像大小或任何内存限制。这是在从网络线程向UI添加字段时发生的。异常不是由于图像大小或任何内存限制造成的。这是在从网络线程向UI添加字段时发生的。