tmh*_*tmh 0 sockets android client-server freeze
我认为这是一个很常见的问题,但我仍然找不到满意的答案,所以我会问自己.
这是一段代码:
// 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!");
}
Run Code Online (Sandbox Code Playgroud)
这就是我想要实现的目标:
但是当用户单击"发送"按钮时,UI会冻结(奇怪地在状态文本出现之前),直到通信完成(我尝试连接到未知主机).快速修复是设置套接字超时,但我不喜欢这种解决方案:UI仍然冻结,应该设置哪个超时?
我的第一个想法显然是Thread,但正如你所看到的,我需要返回一个值,因为线程独立且异步地运行,所以在线程环境中没有多大意义.
所以我需要的是UI肯定等待服务执行但没有冻结.顺便说一句,在我看来,等待返回值意味着UI 必须等待任务结束,我不会让它冻结.
我遇到了AsyncTask,但我发现两个主要缺点:
AsyncTask<Object, Void, Void>吗?两者都导致无法表达.
我能做些什么来实现我的目标?请注意,对该服务的另一个请求是对尚未准备好的东西的请求,所以我应该每隔几次自动重复请求(比方说十分钟).所以我可能需要一些我可以使用的东西TimerTask,但是每次执行该服务时我仍然需要向UI返回一个值(所以我可以更新状态文本并让用户知道发生了什么).
这是通过外部通信(即HTTP调用)进行处理时的典型用例.
最好的方法是使用AsyncTask.为您提供有关AsyncTask问题的答案.
在我看来,它与UI紧密耦合;
这里好的代码设计将发挥作用.您可以编写自己的回调机制来摆脱紧耦合.示例可以在下面.
为WS调用所需的请求和响应创建您的版本.它可以是非常简单的原始类型或复杂类型参数.
class Result{
//Define more para.
Run Code Online (Sandbox Code Playgroud)
}
class Request{
//Deinf more para.
}
Run Code Online (Sandbox Code Playgroud)
写下面的回调接口.
public interface MyCallBack {
public void onComplete(Result result);}
Run Code Online (Sandbox Code Playgroud)
创建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
}
}
Run Code Online (Sandbox Code Playgroud)
现在最后和重要的部分实现接口并调用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!");
}
}
Run Code Online (Sandbox Code Playgroud)
如果我想用Integer,String和Boolean参数执行服务怎么办?我应该扩展AsyncTask吗?
第一个参数是任何用户定义的段.如果您需要传递多个参数,则将它们放入实体形式(即 - 类).此外,您可以在AsyncTask的构造函数中传递初始配置参数,即 - 通信URL.
希望它会有所帮助.
| 归档时间: |
|
| 查看次数: |
1875 次 |
| 最近记录: |