—————————————————————————————————————————————————————————————————————————————
开发环境:eclipse +4.0android SDK+串口调试工具
前言:这周的任务是为了 完成socket客户端在安卓平台的开发,能够和服务端正常进行收发信息(还未实现汉字)。开始在网上找了很多程序用来参考,结果都不行,发现android3.0以后就不能在主线程(ui线程)中进行socket网络通信!!看来找的程序比较老了,后来有幸找到了极客学院的一个视频,按照上面的方法直接实现了一下,它的比较简单,所以我又稍微优化了一下,而且它的程序还是有一点小bug的,我修改了一下,不过还有待加强。
ps:模拟器和手机上都能成功运行
首先附上极客学院的视频地址:http://www.iqiyi.com/w_19rtlpgvl1.html
效果图片:
客户端(界面)
服务端:(串口调试助手)
正常通信
超时,即socket连接不上
极客学院中的视频的小bug就是在doInBackground中使用了toast,这个应该是不允许的。
还有就是它的代码中用到了异步通信AsyncTask,我遇到的困难都是因为对它不了解,导致出了很多低级的错误,浪费了我很多的时间,给大家一个链接可以学习一下。
自己的错误也在代码中进行了注释,希望能帮助到大家。
大家可以参考这个链接学习 http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html
自己代码的小特色:
1.可以自己手动输入ip地址和端口号,特别是端口号我们是需要获取数字的,所以这里用了一个Integer.parseInt的方法,当然还增加了一个断开连接。
2.利用了socket.connect这个接口,来判断socket是否连接超时,即服务器连接不上,错误的原因有很多,ip不对啊,端口不对,服务器关闭等等。
个人感觉 android socket客户端的操作流程大致是:
1.首先new 一个socket,然后用ip和端口去初始化它。
2.然后初始化它的outputstream和inputstream,输入输出流,当客户端发数据是操作它的输出流,接受数据是操作它的输入流,将他们放入我们的buf中,最后再对buf进行操作。
ps:其实是比较简单,对我来说很难的应该就是语法吧,很多类的规则和方法不知道怎么去调用,特别是doinbackground中不能操作主线程中的控件和变量真是让我浪费了很久的时间。
附上代码:
代码中我作了一点注释
package com.lzj.example.msocketclient;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.InetSocketAddress;import java.net.Socket;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.text.method.ScrollingMovementMethod;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { private EditText ip=null,port=null; private EditText editTest=null; private TextView text=null; private Button send_btn=null,con_btn=null,discon_btn=null; private int port_num=0; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lmain); ip=(EditText)findViewById(R.id.ip); port=(EditText)findViewById(R.id.port); editTest=(EditText)findViewById(R.id.editText); text=(TextView)findViewById(R.id.textView); text.setMovementMethod(ScrollingMovementMethod.getInstance());//使能textview滚动属性 con_btn=(Button)findViewById(R.id.con_btn); con_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { connect(); send_btn.setEnabled(true); editTest.setEnabled(true); } }); send_btn=(Button) findViewById(R.id.send_btn); send_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { send(); } }); discon_btn=(Button)findViewById(R.id.discon_btn); discon_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { close(); } }); send_btn.setEnabled(false); editTest.setEnabled(false); } //-------------socket 实现-------------------------- Socket socket=null; BufferedWriter bw=null; BufferedReader br=null; /*android4.0后不能在主线程(UI线程)中初始化socket,进行socket网络通信,所以我们用asynctask(异步)来将这个过程放到后台*/ public void connect(){ AsyncTask<Void, String, Void> read=new AsyncTask<Void, String, Void>(){ /*doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。 * 在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。*/ protected Void doInBackground(Void... arg0) {//doinbackground该方法中不能对UI当中的空间进行设置和修改 //将输入端口的editText中获取的string转化为int port_num=Integer.parseInt(port.getText().toString().trim()); /*字节流转换成字符流可以用 InputSteamReader OutputStreamWriter 转换成BufferdReader BufferedWriter 他们具有缓冲区 */ socket=new Socket(); String line; //用connect延时3秒来看客户端是否连接服务器 try { socket.connect(new InetSocketAddress(ip.getText().toString(),port_num ),3000); bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); br=new BufferedReader(new InputStreamReader(socket.getInputStream())); publishProgress("@连接成功"); //readline是以\n结尾,所以send函数中的write方法中需要加+\n /*这个地方是我出错的地方,只是把上面3句用try catch包围!当第一次输入错误ip的时候 * 程序会退出,是因为我把下面这个循环用try catch包围了,因为下面用到了br变量 * 如果前面出错那么这个变量则不会被初始化!! * 同样不能再catch中用toast,因为不能在非ui线程中使用它,doinbackground是在后台运行 * 切记!花了我太久太久的时间了!*/ while ((line=br.readLine())!=null){ publishProgress(line); } } catch (IOException e1) { try {//异常检查,如果超时或者断开连接则则执行下面操作 publishProgress("@连接失败(超时or断开)"); socket.close(); } catch (IOException e) { e.printStackTrace(); } e1.printStackTrace(); } return null; } /*onProgressUpdate(Progress…) * 可以使用进度条增加用户体验度。 * 此方法在主线程执行,用于显示任务执行的进度。 * 这里是可以执行主线程中的设置,所以可以用toast*/ protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); if(values[0].equals("@连接成功")){ Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show(); } text.append("服务器:"+values[0]+"\n"); } }; read.execute();//执行 } /*发送信息的函数*/ public void send() { try { text.append("本机:"+editTest.getText().toString()+"\n"); bw.write(editTest.getText().toString()+"\n"); bw.flush(); editTest.setText(""); } catch (IOException e) { e.printStackTrace(); } } /*关闭socket函数,即断开连接*/ public void close(){ try { socket.close(); Toast.makeText(MainActivity.this,"断开连接" ,Toast.LENGTH_SHORT).show(); send_btn.setEnabled(false); editTest.setEnabled(false); } catch (IOException e) { e.printStackTrace(); } }}
xml文件:
<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:background="@drawable/bk" tools:context="${relativePackage}.${activityClass}" > <EditText android:id="@+id/ip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/con_btn" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/con_btn" android:hint="请输入服务器ip地址" android:textColorHint="#ffff" android:ems="10" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_marginBottom="70dp" android:hint="编辑内容" android:textColorHint="#0000" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/send_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_marginBottom="28dp" android:text="发送" android:textStyle="bold" /> <Button android:id="@+id/con_btn" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/discon_btn" android:text="连接" android:textStyle="bold" /> <Button android:id="@+id/discon_btn" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/con_btn" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:text="断开" android:textStyle="bold" /> <!-- 设置textview下拉属性 scrollbars “滚动条出现到消失的时间=5000ms” --> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/editText" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_below="@+id/port" android:scrollbarFadeDuration="5000" android:scrollbarStyle="insideOverlay" android:scrollbars="vertical" android:textColorHint="#ffff" android:hint="聊天区域"/> <EditText android:id="@+id/port" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/ip" android:layout_toLeftOf="@+id/con_btn" android:ems="10" android:hint="请输入服务器端口号" android:textColorHint="#ffff" android:inputType="number" /></RelativeLayout>
<uses-permission android:name="android.permission.INTERNET"/>
下一篇地址: http://blog.csdn.net/liuzijiang1123/article/details/50365546
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow