0

我正在使用 ListField 控件来显示从 xml webservice 返回的数据。我想每分钟刷新一次 ListField 或屏幕,以使用新记录或数据更新 ListField。

我尝试使用下面的代码,但它不能正常工作(它挂起)。

public MyApp() {
    // Push a screen onto the UI stack for rendering.
    UiApplication.getUiApplication().invokeLater(new Runnable() {
        public void run() {
            UiApplication.getUiApplication().pushScreen(new MyScreen());
        }
    },5000,true);
}
ResponseHandler handler = new ResponseHandler();
ListField listUsers = new ListField(handler.getItem().size());

public MyScreen() {
    setTitle("yQAforum");
    //Fetch the xml from the web service
    String wsReturnString = GlobalV.Fetch_Webservice("myDs");
    //Parse returned xml
    SAXParserImpl saxparser = new SAXParserImpl();
    ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
    try {
        saxparser.parse( stream, handler );
    } 
    catch ( Exception e ) {
        response.setText( "Unable to parse response.");
    }
    //Return vector sze from the handler class
    listUsers.setSize(handler.getItem().size());
    listUsers.setCallback(this);
    listUsers.setEmptyString("No Users found", 0);
    add(listUsers);
}
4

1 回答 1

2

您正在尝试从 UI 线程上的 Web 服务获取数据。这几乎总是错误的做法。

UI 线程(也称为线程)负责绘制 UI,并跟踪用户操作,如触摸,或通过触控板/轨迹球进行导航。如果 UI 线程在等待远程 Web 服务器响应时被阻塞,则它无法为 UI 提供服务。

您应该进行一些更改:

public MyApp() {
    // Push a screen onto the UI stack for rendering.
    UiApplication.getUiApplication().invokeLater(new Runnable() {
        public void run() {
            UiApplication.getUiApplication().pushScreen(new MyScreen());
        }
    },5000,true);
}

应该改为

public MyApp() {
    // Push a screen onto the UI stack for rendering.
    pushScreen(new MyScreen());
}

构造MyApp()函数将已经在 UI 线程上调用,因此无需使用在 UI 线程上invokeLater()执行pushScreen()调用。MyApp如果从构造函数中运行,它将在 UI 线程上调用。此外,5000 毫秒的延迟并没有真正的帮助。这只会将您的应用程序的启动延迟 5 秒,这是用户会讨厌的。

如果您正在尝试实现启动画面或类似的东西,当应用程序启动时,请在堆栈溢出中搜索“黑莓启动画面”,我相信您会找到结果。

现在,一旦您的MyScreen类被创建,您应该注意不要从 UI 线程获取 Web 服务结果。构造MyScreen函数将在 UI 线程上运行。如果需要,您可以在屏幕显示后在后台线程上发起Web 服务请求。一种方法是使用onUiEngineAttached()

protected void onUiEngineAttached(boolean attached) {
    if (attached) {
        // TODO: you might want to show some sort of animated
        //  progress UI here, so the user knows you are fetching data

        Timer timer = new Timer();
        // schedule the web service task to run every minute
        timer.schedule(new WebServiceTask(), 0, 60*1000);
    }
}

public MyScreen() {
    setTitle("yQAforum");

    listUsers.setEmptyString("No Users found", 0);
    listUsers.setCallback(this);
    add(listUsers);
}

private class WebServiceTask extends TimerTask {
    public void run() {
        //Fetch the xml from the web service
        String wsReturnString = GlobalV.Fetch_Webservice("myDs");
        //Parse returned xml
        SAXParserImpl saxparser = new SAXParserImpl();
        ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
        try {
           saxparser.parse( stream, handler );
        } 
        catch ( Exception e ) {
           response.setText( "Unable to parse response.");
        }
        // now, update the UI back on the UI thread:
        UiApplication.getUiApplication().invokeLater(new Runnable() {
           public void run() {
              // TODO: record the currently selected, or focused, row

              //Return vector sze from the handler class
              listUsers.setSize(handler.getItem().size());
              // Note: if you don't see the list content update, you might need to call
              //   listUsers.invalidate();
              // here to force a refresh.  I can't remember if calling setSize() is enough.

              // TODO: set the previously selected, or focused, row
           }
        });
    }
}

您需要添加一些错误处理,以防 Web 服务没有响应或花费超过一分钟的时间(如果最后一个请求尚未完成,您不希望发出新请求)。

但是,这应该让你开始。

注意:一旦你解决了在 UI 线程上运行网络代码的问题,你可能仍然会发现你的代码不起作用。获取 Web 服务数据可能存在问题。你必须调试它。我只向您展示发布代码的一个问题。如果您仍然对 Web 服务获取有问题,请发布另一个问题(已修复 UI 线程问题)。谢谢。

于 2012-12-27T21:46:39.403 回答