1

我是黑莓开发新手,我正在创建一个原生黑莓应用程序。在我的应用程序的每个屏幕上,我都需要在同一连接上向服务器发送和接收数据。

到目前为止,我所做的是我创建了一个ConnectToServer类,它有一堆发送和接收的方法。我在主屏幕上实例化它,并将它作为参数传递给每个屏幕。

那个类不是线程,因为我只在用户输入信息并按下按钮时读写。所以基本上我在我听到的事件线程上使用 inputStream 和 outputStream 是BAD。然后我要求ConnectToServer得到服务器发送的内容。例如,我得到一个用于制作 ListField 的向量。

如何进行这些 UI 更新?

public class Screen3 extends MainScreen {

  ConnectToServer con;
  Vector v;

  public Screen3(String exerciseName, ConnectToServer connect)
  {
      con = connect;
      con.send(exerciseName);
      v = con.receiveVector();

      mylist = new listField();
      mylist.setSize(v.size());
      add(mylist);
   }

   public void drawListRow(...)
   {
      graphics.drawText((String) v.elementAt(index)
   }
}
4

1 回答 1

0

所以,有很多方法可以解决这个问题。首先,由于您似乎只想要一个 的实例ConnectToServer,而您目前不得不传递它,您可以尝试将该类设为Singleton 对象这不是必需的,并且与您的线程问题没有任何关系,但我仅将它作为一种解决方案提供,用于您想要强制只有一个实例的情况,并希望避免传递它到处。一个简单的 Singleton 实现可能是这样的:

public class ConnectToServer {

    private static ConnectToServer _instance;

    /** use this static method to get the one and only instance */
    public static ConnectToServer getInstance() {
        if (_instance == null) {
            _instance = new ConnectToServer();
        }
        return _instance;
    }

    /** private to enforce Singleton pattern */
    private ConnectToServer() {
    }
}

并像这样在屏幕中使用它(不再需要将其传递给构造函数):

ConnectoToServer connection = ConnectToServer.getInstance();
connection.blahBlahBlah();

现在,关于线程问题。你是对的,你不应该在主(又名“UI”,又名“事件”)线程上执行网络请求。如果您有一个不错的单独ConnectToServer类,则可以更轻松地封装此行为。代替使用同步 send()receiveVector()方法的 UI 客户端,创建一个仅启动请求的方法,以及ConnectToServer该类将在响应返回时调用的另一个回调方法。该类ConnectToServer将使用 aThread来执行这项工作,从而避免在请求期间冻结 UI。

我将定义interfaceUI 客户端将实现的:

public interface RequestListener {

    /** listeners must implement this method to get data.  method will be called on the UI thread */
    void onDataReceived(Vector response);
}

然后是新的(部分)ConnectToServer类:

public class ConnectToServer {
    private Thread _worker;
    private RequestListener _listener;

    public void setRequestListener(RequestListener listener) {
        // note: this implementation only allows one listener at once.  
        //  make it a list if you need something more
        _listener = listener;
    }

    /** initiate a network request on a background thread */
    public void sendRequest(final String request) {
        _worker = new Thread(new Runnable() {
            public void run() {    // run on the background/worker thread
                send(request);

                final Vector response = receiveVector();

                if (_listener != null) {
                    // this assumes all our listeners are UI objects, so we pass 
                    //   data back to them  on the UI thread:
                    UiApplication.getUiApplication().invokeLater(new Runnable() {
                        public void run() {    // run on UI thread                
                            _listener.onDataReceived(response);
                        }
                    });
                }
            }
        });

        _worker.start();
    }
}

请注意,您还应该在此类中制作您的原始 send()和方法。现在只能从类内部调用它们,而不是直接从 UI 客户端调用。receiveVector()private

然后,您需要Screen像这样编写您的类:

public class Screen3 extends MainScreen implements RequestListener {

    public Screen3(String exerciseName) {
        ConnectToServer connection = ConnectToServer.getInstance();
        connection.setRequestListener(this);
        // kick off the request (on a background thread)
        connection.sendRequest(exerciseName);
    }

    public void onDataReceived(Vector response) {
         if (mylist == null) {
             // first time data has been received, so create and add the list field:
             mylist = new listField();            
             add(mylist);
         }
         mylist.setSize(response.size());
         // TODO: presumably, you would copy the contents of 'response' into 'mylist' here  
    }
}

此外,您可能还希望对服务器类进行编码以防止多个 UI 客户端发出并发请求、允许取消当前请求等。但以上内容应该让您开始使用提供响应式应用程序的解决方案,而不会冻结您的 UI .

于 2012-09-14T21:53:40.007 回答