我想为Android构建一个简单的tcp客户端。 客户端需要先发送名称和密码,然后保持与服务器的连接,直到应用程序关闭(如果由于某种原因而失去连接,则需要通过发送用户名和密码来重新建立连接)。
现在,我实现了一些简单的客户端,如下所示:
public class SendRecvAsynch extends AsyncTask<String, String, TcpClient> {
final String SERVER_IP = "10.0.0.7"; //server IP address
final int SERVER_PORT = 1234;
String modifiedSentence;
EditText tv = (EditText) findViewById(R.id.editText_main);
@Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object
try {
// create address
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
try {
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
// create in out stream
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// write to server and get response
outToServer.writeBytes("hello from client");
// read from server
modifiedSentence = inFromServer.readLine();
if (modifiedSentence == null)
{
modifiedSentence = "didn't get a dame thing from the server";
}
// close the socket
socket.close();
}catch (IOException e) {
tv.setText(e.toString());
e.printStackTrace();
}
} catch (UnknownHostException e) {
tv.setText("got exceptin");
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
tv.setText(modifiedSentence);
//response received from server
Log.d("test", "response " + values[0]);
//process server response here....
}
}
我从OnCreate
这样的方法启动客户端:
new SendRecvAsynch().execute("");
我希望该应用程序可以连接服务器,向他发送“来自客户端的问候”,等待服务器响应并关闭套接字连接。
收到响应后,我希望AsyncTask
更新我在应用主屏幕上的EditText
框。
问题在于此AsyncTask
不会更新EditText
...我在服务器端看到该应用已连接并向服务器发送了“来自客户端的问候”,但我没有从客户端看不到服务器的响应...
我猜测由于某种原因,后台进程无法访问属于主线程的主屏幕,我该如何更改呢? 如何创建可以从服务器发送和接收线路的简单tcp客户端?
谢谢。
答案 0 :(得分:0)
是的,在android系统中,禁止在主线程之外访问更新UI(在您的情况下为EditText
)。
但是由于这个原因,AsyncTask
具有onPostExecute()
方法,您可以在其中直接从主线程运行代码。
因此,您唯一要做的就是覆盖onPostExecute()
并在SendRecvAsynch
中实现DROP TABLE IF EXISTS #TestTable1
DROP TABLE IF EXISTS #TestTable2
CREATE TABLE #TestTable1 ([No] varchar(50),[Value1] float,[Desc] varchar(50))
insert into #TestTable1 ([No],[Value1],[Desc])
Values
(N'123953',300.02,N'Extra Pay')
,(N'123953',427.2,N'Basic Hours')
,(N'123953',106.8,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',105.6,N'Basic Hours')
CREATE TABLE #TestTable2 ([No] varchar(50),[Value2] float,[Desc] varchar(50))
insert into #TestTable2 ([No],[Value2],[Desc])
Values
(N'123953',200.02,N'Extra Pay')
,(N'123953',553.02,N'Basic Hours')
,(N'123953',446.67,N'Basic Hours')
,(N'123953',427.2,N'Basic Hours')
,(N'123953',106.8,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',213.6,N'Basic Hours')
,(N'123953',105.6,N'Basic Hours')
以适应您的需求。
答案 1 :(得分:0)
您应该看看runOnUiThread method。
来自Android's Developers website:
public final void runOnUiThread(可运行操作)
在UI线程上运行指定的操作。如果当前线程是UI线程,则立即执行该操作。如果当前线程不是UI线程,则将操作发布到UI线程的事件队列。
即使您可以使用runOnUiThread
解决问题,但我还是强烈建议您切换不久前引入的新Architecture Components。特别看一下ViewModel和LiveData组件。这是Guide to app architecture。