0

我认为这是一个很常见的问题,但我仍然没有找到满意的答案,所以我要问自己。

这是一段代码:

// this is insine OnClickView
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
try {
    // this opens a socket and send a login request to the server.
    int result = CommunicationManager.login(String email, String password);
    switch (result) {
    case CommunicationManager.SUCCESS:
        // login ok, go on with next screen
        break;
    case CommunicationManager.WRONG_EMAIL:
        status.setTextColor(Color.RED);
        status.setText("Wrong Email!");
        break;
    case CommunicationManager.WRONG_PASSWORD:
        status.setTextColor(Color.RED);
        status.setText("Wrong Password!");
        break;
    }
} catch (CommunicationException e) {
    status.setTextColor(Color.RED);
    status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
    status.setTextColor(Color.RED);
    status.setText("Protocol error!");
}

这就是我想要实现的目标:

  1. 用户点击发送按钮;
  2. status textview 显示“正在尝试连接到服务器...”;
  3. UI“等待”通信结束;
  4. status textview 相应地显示结果。

但是,当用户单击“发送”按钮时,UI 会冻结奇怪的是在状态文本出现之前),直到通信完成(我尝试连接到未知主机)。一个快速的解决方法是设置套接字超时,但我不喜欢这种解决方案:UI 仍然冻结,应该设置哪个超时?

我的第一个想法显然是 Thread ,但是正如您所见,我需要返回一个 value,这在线程环境中没有多大意义,因为线程独立且异步运行。

所以我需要的绝对是 UI 等待服务执行但没有冻结。顺便说一句,在我看来,等待返回值意味着 UI必须等待任务结束,我只是不会让它冻结。

我遇到了 AsyncTask,但我看到了两个主要缺点:

  1. 在我看来,这与 UI 耦合太紧密了;
  2. 如果我想使用 Integer、String 和 Boolean 参数执行服务怎么办?我应该延长AsyncTask<Object, Void, Void>吗?

两者都导致不可扩展性。

我能做些什么来实现我的目标?请注意,对服务的另一个请求将是对尚未准备好的内容的请求,因此我应该每隔几次(假设十分钟)自动重复请求。所以可能我需要一些我可以使用的东西TimerTask,但我仍然需要在每次执行该服务时向 UI 返回一个值(这样我可以更新状态文本并让用户知道发生了什么)。

4

3 回答 3

6

这是通过外部通信(即 HTTP 调用)处理时的典型用例。

最好的方法是使用 AsyncTask。为您解答您对 AsyncTask 的担忧。

在我看来,这与 UI 耦合太紧密了;

在这里,良好的代码设计将发挥作用。您可以编写自己的回调机制来摆脱紧密耦合。示例如下。

为 WS 调用所需的请求和响应创建版本。它可以是非常简单的原始类型或复杂类型参数。

class Result{
    //Define more para.

}

class Request{
    //Deinf more para.
}

写在回调接口下面。

public interface MyCallBack {
     public void onComplete(Result result);}

在构造函数中创建 AsyncTask 并获取上面的 Interface 对象,相同的对象可以返回 Result 对象。

    class LongRunningTask extends AsyncTask<Request, Integer, Long>{
    private MyCallBack callback;
    public LongRunningTask(MyCallBack callback) {
        super();
        this.callback = callback;
    }
    @Override
    protected Long doInBackground(Request... params) {
        // Perform your back ground task.
        return null;
    }
    @Override
    protected void onPostExecute(Long result) {
        super.onPostExecute(result);            
        callback.onComplete(new Result()); //Here result is dummy but in real it should be contructred from doInBackground() method
    }
}

现在是实现接口和调用 asynctask 的最后一个重要部分。我正在尝试重用您的代码以提高清晰度。

public class MainActivity extends Activity implements MyCallBack{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView status = (TextView) findViewById(R.id.status);
    status.setText("Trying to connect to the server...");
}

private void onClick(){
    //Similer to CommunicationManager.login(String email, String password); in your code.
    LongRunningTask longRunningTask = new LongRunningTask(this);
    longRunningTask.execute(new Request());
}

@Override
public void onComplete(Result result) {     
    try {

        int result = result.getStatus 
        switch (result) {
        case CommunicationManager.SUCCESS:
            // login ok, go on with next screen
            break;
        case CommunicationManager.WRONG_EMAIL:
            status.setTextColor(Color.RED);
            status.setText("Wrong Email!");
            break;
        case CommunicationManager.WRONG_PASSWORD:
            status.setTextColor(Color.RED);
            status.setText("Wrong Password!");
            break;
        }
    } catch (CommunicationException e) {
        status.setTextColor(Color.RED);
        status.setText("Unable to estabilish a connection!");
    } catch (ProtocolException e) {
        status.setTextColor(Color.RED);
        status.setText("Protocol error!");
    }
}

如果我想使用 Integer、String 和 Boolean 参数执行服务怎么办?我应该扩展 AsyncTask 吗?

第一个参数是任何用户定义的参数。如果您需要传递多个参数,然后将它们放入实体的形式(即 - 类)。此外,您可以在 AsyncTask 的构造函数中传递初始配置参数,即 - 通信 URL。

希望它会有所帮助。

于 2013-02-17T11:36:47.480 回答
0

使用多线程,在不同的线程中进行所有通信

于 2013-02-17T11:08:29.550 回答
0

使用工作线程或 AsyncTask 执行长时间运行的操作。

此外,从 Android Honeycomb 开始,如果您在 UI 线程上执行网络操作,系统会抛出异常。

于 2013-02-17T11:42:09.200 回答