您的位置:首页 > 理论基础 > 计算机网络

简单的Android TCP Client(Android非UI线程修改界面)

2014-07-17 17:10 281 查看
http://www.cnblogs.com/zealoct/p/3193160.html

写一个简单的Android TCP Client的测试程序,可以向Emulator外的TCP Server发送消息,并显示服务器的返回信息。



因为这是个很简单的小应用,本来就没想要多线程,结果在运行的时候出现如下错误:

W/System.err(  755): android.os.NetworkOnMainThreadException


原来在主进程中进行网络操作会被Android Framework给毙掉,所以新建了一个线程来进行tcp读写,再次运行又出现如下错误:

W/System.err(  853): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.


原来只有创建UI的那个线程可以对UI进行修改,我实现的时候方便起见在新开线程中直接修改了TextView的内容,自然会出错。

这种很严格的程序限制可以增强应用的可靠性,或许会觉得Android给开发者设定诸多限制会影响开发效率,难道写个这么短小的东西都要实现进程间通信么?其实Android Framework本身就提供了相应的解决方案,我们可以利用下面几个方法来实现这一功能:

void Activity.runOnUiThread(Runnable action)

该方法把action添加到指定的UI进程的事件队列中去,如果当前进程就是该UI进程,那么action会立刻被执行。

Boolean View.post(Runnable action)

Booleqn View. postDelayed (Runnable action, long delayMillis)

这两个方法把action添加到特定UI元素的事件队列中区,前者直接加入消息队列等待执行,后者等待指定的时间间隔后执行。

利用以上API,很好的解决了UI修改的问题:

public class MainActivity extends Activity implements OnClickListener {
public static final String TAG = "testServer";

TextView TextViewOutput;
EditText EditTextMsg;
String msg;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button BtnSend = (Button) this.findViewById(R.string.BtnSend);
TextViewOutput = (TextView) this.findViewById(R.string.TextViewOutput);
EditTextMsg = (EditText) this.findViewById(R.string.EditTextMsg);

BtnSend.setOnClickListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
msg = EditTextMsg.getText().toString().trim();

if(msg.length() == 0) {
TextViewOutput.append("cannot send blank msg\n");
return;
}

Thread thread = new Thread(new NetThread(), "thread1");
thread.start();

EditTextMsg.setText("");
}

class NetThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Socket socket=new Socket("10.0.2.2", 2000);
PrintWriter pw =new PrintWriter(socket.getOutputStream());

TextViewOutput.post(new ChangeText("Sending:" + msg));
pw.println(msg);
pw.flush();
MainActivity.this.runOnUiThread(new ChangeText("...finished!\n"));

Scanner scan = new Scanner(socket.getInputStream());
String ret = scan.nextLine();
TextViewOutput.post(new ChangeText("Return:" + ret + "\n"));

pw.close();
scan.close();

socket.close();
} catch (Exception EE) {
EE.printStackTrace();
}
}
}

class ChangeText implements Runnable {
String text;
ChangeText(String text) {
this.text = text;
}
@Override
public void run() {
// TODO Auto-generated method stub
TextViewOutput.append(text);
}
}
}


另贴上一小段Server.rb

require 'socket'

server = TCPServer.new(2000)
loop {
client = server.accept
thread = Thread.new {
while msg = client.gets
puts "RECV: #{msg}"
client.puts "ret #{msg}"
end
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: