最近要做一个Android的项目,用到socket和服务器之间交互,研究了一个小demo。主要遇到了以下几个问题:
1.客户端创建socket对象时一直失败NetworkOnMainThreadException,查了一下,原因是4.0之后在主线程中执行http请求会报这个错。解决办法是将代码放到了一个新线程中,问题就解决了。
2.服务器接收到客户端信息后反馈给客户端信息,将该信息表示在客户端UI上时报“android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.”异常。该问题原因是,在主线线程之外的线程中直接更新页面显示常会报错。解决办法是通过runOnUiThread方法将线程对象传过去,这样在主线程中就能执行该线程的内容了,当然还有其他办法。可参考链接http://blog.csdn.net/shenyuemei/article/details/11030679。
下面是程序代码:
布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/et_hint" /> <Button android:id="@+id/send" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/txt_send" /> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
服务端代码
package testDemo; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server implements Runnable { public static void main(String[] args) { Thread desktopServerThread = new Thread(new Server()); desktopServerThread.start(); } @Override public void run() { try { ServerSocket serverSocket = new ServerSocket(8888); while (true) { // 阻塞,等待接收客户请求。 Socket client = serverSocket.accept(); System.out.println("接受到客户端的请求。"); try { BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream())); // 读取客户端发过来的信息 String read = in.readLine(); System.out.println("客户端发送消息为 : " + read); // 向客户端返回信息 PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(client.getOutputStream()))); if (read != null) { out.println("你发送给服务器的信息为 : " + read); out.flush(); } out.close(); in.close(); } catch (Exception e) { e.printStackTrace(); } finally { client.close(); } } } catch (Exception e) { e.printStackTrace(); } } }
客户端代码
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class ClientActivity extends Activity { private Button send = null; private EditText content = null; private TextView tv = null; String msg = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.socket2); send = (Button)findViewById(R.id.send); content = (EditText)findViewById(R.id.content); tv = (TextView)findViewById(R.id.tv); send.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { setTitle("socket"); new Thread(thread1).start(); } }); } /*Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { myHandler.post(thread1); } };*/ /** * 该线程主要是向服务器发送消息和接收消息 */ Runnable thread1 = new Runnable() { @Override public void run() { Socket socket = null; try { InetAddress serverAddr = InetAddress.getByName("192.168.1.110"); socket = new Socket(serverAddr, 8888); //想服务器发送消息 PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); out.println(content.getText().toString()); out.flush(); //读取服务器返回的消息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); msg = in.readLine(); //把该子线程当做参数传递,这样在主UI线程就可更新UI ClientActivity.this.runOnUiThread(updateThread); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; Runnable updateThread = new Runnable() { @Override public void run() { if (msg != null) { tv.setText(msg); } else { tv.setText("data error."); } } }; }