Android 4.x版本_子线程socket编程小实例

来源:互联网 发布:mysql启动 编辑:程序博客网 时间:2024/05/17 06:17

这几天在做一个android平台的关于网络通信的项目,之前android学习的不是很多,java语法也一知半解,所以在学习的过程中遇到了很多迷惑,一点点解决起来也十分困难。

所以首先建议初学者最好是先认真的学习java语言,然后再接触安卓开发,这样学习安卓的速度有很大提升,而且对于扎实的学习很有帮助。


在安卓4.0版本以后,无法在主线程中访问网络。因为访问网络的话,如果因为一些网速原因或者手机处理器慢等等原因,造成了延迟大于五秒(好像是这个时间),那么主线程(activity)会造成系统警报,报错。所以安卓4.0以后的系统版本将socket访问网络规定为只能在 子线程中进行。


下面是一个服务器和手机客户端的交互实例。


功能:手机端接受一条来自服务器的string数据并且显示。


界面:测试用的demo,所以随便拖了一个textview和button进去,IDE上随便用鼠标拖了一下位置。

代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".MainActivity" >    <TextView        android:id="@+id/textView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />    <Button        android:id="@+id/button1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignTop="@+id/textView1"        android:layout_centerHorizontal="true"        android:text="Button" /></RelativeLayout>

服务器端代码:

import java.io.BufferedWriter;import java.io.IOException;import java.io.OutputStreamWriter;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;public class SerMachine {//PORT 变量代表服务器端口 private static final int PORT = 40001; public static void main(String[] args) {//socket类的实例化对象建立,必须放在try里面,这是规定   try {    // 实例化服务器套接字 设置端口号9999   ServerSocket server = new ServerSocket(PORT);    //服务器端的ServerSocket对象是不需要关闭的,如代码最后所示,只需要关闭流对象就可以了   while (true) {   //socket中的阻塞不是由while(true)产生的,而是由accept产生的    Socket socket = server.accept();    //如果accept没有接受到客户端的接入请求的话,就会一直阻塞在这里    //所以一个服务器面向多个客户端的时候,都是用多线程socket的    //就是说为每一个来访的客户端配置一个子线程,每个线程用来负责一个客户端    //客户端的所有请求都在对应的子线程中处理    //对应的,服务器接受客户端发来的数据可以使用BufferedReader + InputStreamReader    //此处是向客户端发送数据,所以用BufferedWriter + OutputStreamWriter    //曾经我试过OutputStream writer=(OutputStream) socket.getOutputStream();    //但是我没有调出来,经过鉴定还是上述的B+I和B+O的组合最好用,可行性强,比较简单    //上面OutputStream = socket.getOutputStream这种写法是我看李刚老师的疯狂android看到的    //我还试过printStream等等好多流,反正只有B+I+O成功了    //下面就是获取输出流    BufferedWriter writer = new BufferedWriter(      new OutputStreamWriter(socket.getOutputStream()));    //向客户端发送string数据    writer.write("Messages come from SerMachine");    //每次发送完数据都要刷新一下,据说这这样比较好    writer.flush();    //关闭流    writer.close();   }   //抛出异常是必须的!必须的!必须的!  } catch (UnknownHostException e){  // TODO Auto-generated catch block  e.printStackTrace();  } catch (IOException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }}

下面是客户端的代码:

package com.example.service_behind2;import android.os.Bundle;import android.app.Activity;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; import android.annotation.SuppressLint; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;  @SuppressLint("HandlerLeak")//上面这句话可有可无,网上有说明,大家可以自行百度public class MainActivity extends Activity {//先建立两个对象,用来获取xml中的控件 private Button receive_button; private TextView MessageShow; //这个string用来保存从服务器接受来的信息 private String message_from_sermachine;  //HOST表示IP地址,这是我的电脑联网时候的IP地址 //服务器也是运行在我的电脑上,所以IP地址就是这个 private static final String HOST = "121.229.136.83";  //PORT表示对应端口,必须和服务器的ServeSocket端口一样 private static final int PORT = 40001;  //查看IP的方法是:开始-》运行-》cmd-》ipconfig-》ppp适配器-》Ipv4 @Override public void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  //通过R.id找到对应的xml控件  receive_button = (Button) findViewById(R.id.button1);  MessageShow = (TextView) findViewById(R.id.textView1);  //给receive_button添加事件监听器  receive_button.setOnClickListener(new ReceiverListener()); }  @SuppressLint("HandlerLeak") //上面这行代码同理 class ReceiverListener implements OnClickListener { //实现OnClickListener接口  @Override  public void onClick(View v) {   // TODO Auto-generated method stub   new Thread() {   //点击button后,会开一个新的线程!    @Override    public void run() {    //重写线程中的run方法     try {      // 实例化Socket对象      Socket socket = new Socket(HOST, PORT);      // 获得输入流      //此处同理,请见服务器端代码注释      BufferedReader br = new BufferedReader(        new InputStreamReader(socket.getInputStream()));      message_from_sermachine = br.readLine();            //message_from_sermachine.getBytes("utf-8");      //这行代码注释掉是因为有没有都一样      //从服务器接受到的string,编码方式和android不一样      //android用的是utf-8编码      //所以造成了服务器传输中文汉字时候不能被客户端正确解码的现象      //会显示一堆乱码,所以我想用getBytes();函数来解决编码问题      //但是失败了,这个实例到现在还是没办法正确显示服务器发来的汉子      //希望有办法的朋友教教我      br.close();      //关闭流      //抛出异常是必须的!     } catch (UnknownHostException e) {      // TODO Auto-generated catch block      e.printStackTrace();     } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();     }     //接受好的数据已经保存在了message_from_sermachine变量里面     //但是就像主线程无法访问网络,只能在子线程访问一样     //更新UI只能在主线程中做,不能在子线程中控制前台UI控件     //所以需要handle类来解决这个问题     //下面调用handler对象的sendEmptyMessage方法     //事实上传出的是空消息     //但是服务器发送来的数据,已经保存在了那个string里面     handler.sendEmptyMessage(0);    }   }.start();   //开启这个线程  } } // 定义Handler对象 private Handler handler = new Handler() {   @Override  //只要接到消息发出,就会执行这个方法  //包括空消息  public void handleMessage(Message msg) {   super.handleMessage(msg);   // 处理前台的UI控件   //将接受的数据,显示在textview里面   MessageShow.setText(message_from_sermachine);  } };}


此外,千万不要忘了在androidManifest文件中添加访问网络的权限。

 <uses-permission android:name="android.permission.INTERNET"/>

这行代码有时候复制会报错,所以建议大家最好是自己重新打一遍。


以上代码的原始版本,最初在某偏僻网站找到,我还算认真的研究了一段时间吧。。。

并且做了适当的修改,是能够正确运行的。

测试的时候,我的API版本是4.2建立的工程。

有任何疑问欢迎大家交流。

原创粉丝点击