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建立的工程。
有任何疑问欢迎大家交流。
- Android 4.x版本_子线程socket编程小实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket编程实例
- android socket 编程实例
- android socket编程实例
- Android socket 编程实例
- Android Socket编程实例
- Android Socket编程实例
- android socket编程实例
- C#网络编程之多线程socket实例
- android之socket编程实例
- android之socket编程实例
- 《说服力》读后总结摘录
- [unity基础教程] Unity3D 一个物体在两个物体间移动
- [unity基础教程]操作transform.localPosition的时候请小心
- 选择是把握人生命运最伟大的力量。
- 6.3 Hibernate的批量处理: (6.3.2)批量更新
- Android 4.x版本_子线程socket编程小实例
- (十六)备忘录模式详解(都市异能版)
- struts2 无刷新调用action 实现页面数据动态加载
- poj 1038 状态压缩~棋盘覆盖
- 6.3 Hibernate的批量处理: (6.3.3)DML风格的批量更新和删除
- struts2 迭代中动态设置div 的ID 《转载》
- 清理Windows.edb文件释放C盘空间(转)
- 记录使用JGraph过程中的点点滴滴
- [C#基础知识]HashMap与Hashtable的区别