IPStringI有一个相当简单的Activity,其工作方式如下: 在onCreate中,我通过专用端口调用与远程服务器的AsyncTask TCP Socket连接,向服务器发送快速ASCII命令并通过onPostExecute()处理响应。效果很好,速度快,功能齐全。
但是,如果远程服务器出现故障 - 或者我错误地输入了错误的IP地址进行通信 - 我的AsyncTask将挂起,并在屏幕上旋转“登录”对话框,只要它需要套接字超时。
过去两天我一直在试图弄清楚如何调用cancel(),但是我失败了。有什么建议? 这是当前的代码:
public class Scratchpad extends AsyncTask<Object, String, String>{
private String returningResponse;
private volatile Socket socket;
@Override
protected void onPreExecute(){
//throw the "Logging In" dialog up
initializeDialog();
super.onPreExecute();
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(String result) {
//send the ASCII result off to the function that parses through it
loginTriggerResult(result);
super.onPostExecute(result);
}
@Override
protected String doInBackground(Object... params) {
/*
* bunch of stuff goes here to strip out the proper
* values from the Object for IP address, Port number etc.
* params[0], params[1] etc.
*
*/
InetAddress serverIP = null;
String IPString = (String) params[1];
int portnumber = (Integer) params[2];
//convert the String "IPString" into an InetAddress
try {
serverIP = InetAddress.getByName(IPString);
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//and then, bingo bango bongo, make the connection with the 'try':
try{
socket = new Socket(serverIP.getHostAddress(), portnumber);
//I tried this too, forcing the timeout... It crashes immediately.
//SocketAddress socketAddress = new InetSocketAddress(serverIP.getHostAddress(), portnumber);
//socket.connect(socketAddress, 3000);
Log.d("networking","Connection Completed");
//bunch of stuff goes here that happens AFTER the solid connection,
//which we never get to if the Socket fails on a "waiting to connect" thing.
//reader.close();
//outputStream.close();
}catch (SocketException e){
e.printStackTrace();
Log.w("socket","socket closed with SocketException");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.w("socket","socket closed with IOException");
}
return returningResponse; //postExecute will handle this.
}
}
我没有收到任何日志消息,直到套接字超时3或4分钟。 我认为必须有一种方法来运行TimerTask或AsyncTask外部的东西来跟踪连接(或不连接)所花费的时间,然后以某种方式“取消”()取消在AsyncTask中运行的'try',但是我一直在做很多风格。
这是常用的东西,而且必须有一个简单的解决方案吗?
更新 我前进的路径是尝试使用AsyncTask中的套接字连接来“监视自己”,如果/当它超时而没有获得可靠的连接 - 触发AsyncTask的cancel()。 我试图在AsyncTask本身内执行此操作,在Cocket超时的IOException catch中使用this.cancel()。
到目前为止,解决方案是在AsyncTask之外实现一个与AsyncTask同时启动的计时器,并在发生了很多秒之后从那里调用取消。 这个解决方案优雅地退出连接尝试,我可以在AsyncTask的onCancelled()节中放置任何类型的Dialog触发器或Toasts。 它不再崩溃,但是:即使任务被取消,套接字仍然在后台尝试连接。
答案 0 :(得分:0)
看起来最简单的解决方案(您已尝试过)似乎是在调用connect时设置超时。你可以发布连接超时失败时生成的堆栈跟踪吗?
答案 1 :(得分:0)
你到底想要做什么?当您输入错误的IP地址或服务器已关闭时检测到?仅显示登录一段时间?我知道你问的是如何取消你的异步任务,但这似乎不是你试图解决的问题的根源。
我认为MisterSquonnk完全正确,您应该只能在调用connect时设置超时持续时间。如果超时不起作用,您的代码中可能还有其他内容被破坏。或者,如果您只想要一些可以让您自己执行超时而无需与套接字相关的内容,请参阅以下内容:
如果您想假设连接失败的时间比套接字超时的时间短,请同时在活动中的同一位置启动一个新的CountDownTimer http://developer.android.com/reference/android/os/CountDownTimer.html。您可以使用任何想要超时的持续时间来启动异步任务。
计时器用完后(调用计时器中的onFinish),在异步任务上调用cancel,否则阻止onPostExecute执行,并在UI中登录尝试失败时执行任何操作。同样,如果登录尝试在计时器用完之前成功,则取消计时器或以其他方式阻止onFinish被调用。