Android开发手记:Socket网络通信
2014-08-24 14:34
405 查看
这个系列的文章就是为了防止以后自己开发的时候忘了怎么回事,提醒自己用的……由于自己Android开发非常非常菜,所以贴上来的代码很有可能像一坨shi一样,如果有新手朋友看到,希望谨慎地作为参考,同时如果有神牛看到的话,非常希望能批评指正。
到现在为止做了两个安卓的app,都跟网络通讯有关,通过WIFI连接电脑上的服务器,然后他们之间互相交流一点数据。目前我会的最简单的实现方法是利用socket,它就像一个文件一样,连接好以后写/读它就可以了。
要注意的是安卓凡是涉及网络的事情,都不允许在主线程中完成,都必须单开一个线程做,否则会抛出异常,名字的意思就是“主线程中有网络操作”。
另外需要注意的是要开启网络权限,第二个app我调了半天收不到数据,最后猛然想起是没有开网络权限导致的…… 这个下面说。
一般我们都是用一个线程的run函数来做我们希望做的网络操作,就像下面这个登录Activity一样:
代码大部分其实没什么用,看几个关键点就可以了……
有一点这个代码里没有的,就是socket的定义,直接
就可以了。
总的来看,过程就是这样的:
1)用户点击按钮,发起网络线程;
2)run函数进入,socket连接;
3)连接正常的话,收数据,
4)告诉handler更新UI。
有时候我们可能希望和服务器进行交互,下面是一个例子:
服务器端就是典型的java/c++网络编程,跟这篇文章要讨论的就没关系了。
一点经验是网络线程能不一直跑着就不要一直跑着,如果是严格的“请求-响应”工作模式的话,最好每次要发起连接的时候发起一个网络线程,发完-收完数据就结束,不然想结束一个线程不是那么轻松的事情。
最后,想正常利用网络,你需要在manifest里面申请网络权限:
暂且先记录这么多吧……
到现在为止做了两个安卓的app,都跟网络通讯有关,通过WIFI连接电脑上的服务器,然后他们之间互相交流一点数据。目前我会的最简单的实现方法是利用socket,它就像一个文件一样,连接好以后写/读它就可以了。
要注意的是安卓凡是涉及网络的事情,都不允许在主线程中完成,都必须单开一个线程做,否则会抛出异常,名字的意思就是“主线程中有网络操作”。
另外需要注意的是要开启网络权限,第二个app我调了半天收不到数据,最后猛然想起是没有开网络权限导致的…… 这个下面说。
一般我们都是用一个线程的run函数来做我们希望做的网络操作,就像下面这个登录Activity一样:
代码大部分其实没什么用,看几个关键点就可以了……
有一点这个代码里没有的,就是socket的定义,直接
Socket socket = null;
就可以了。
public class LoginActivity extends Activity { ImageButton btn; EditText editText; GetThread getThread; //这个是网络线程 Handler handler; //网络线程要是想更新UI,需要一个handler来转消息 THUClient the_app; //这个东西是为了使用全局变量用的,不用看,THUClient是个类名 class GetThread implements Runnable //一般线程用内部类写,然后implements Runnable { public void getMsg() { try { Scanner in = new Scanner(the_app.socket.getInputStream());//输入流包装一下 String gotmsg = in.nextLine();//就像读控制台和读文件一样读就可以了 Message msg = new Message(); msg.obj = gotmsg;//用msg的obj域搭载消息 LoginActivity.this.handler.sendMessage(msg);//这句话就能把msg扔给handler让他去处理了 } catch (UnknownHostException e) { Message msg = new Message(); msg.obj = "net error"; LoginActivity.this.handler.sendMessage(msg); } catch (IOException e) { Message msg = new Message(); msg.obj = "net error"; LoginActivity.this.handler.sendMessage(msg); } } @Override public void run() //启动线程时,启动这个函数 { try { the_app.socket = new Socket(); //实例化socket the_app.socket.connect(new InetSocketAddress(the_app.ip, the_app.port) , 5000);//connect函数,为什么要这么写呢?因为这样可以设置超时时间,比如这里就是5000毫秒 = 5秒 } catch (UnknownHostException e) { Message msg = new Message(); msg.obj = "did not login"; LoginActivity.this.handler.sendMessage(msg); } catch (IOException e) { Message msg = new Message(); msg.obj = "did not login"; LoginActivity.this.handler.sendMessage(msg); }//凡是这种try-catch语句块,都要处理好必要的异常,否则程序很容易崩出去(比如UnknownHostException不处理的话如果服务器没开就崩出去了),我的处理方法是遇到网络异常的时候,通知主线程弹一个Toast,告诉一下用户 if( the_app.socket != null) getMsg(); else { Message msg = new Message(); msg.obj = "did not login"; LoginActivity.this.handler.sendMessage(msg); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_login); the_app = (THUClient) getApplicationContext(); btn = (ImageButton)findViewById(R.id.buttonId); editText = (EditText) findViewById(R.id.editTextId); Context ctx = LoginActivity.this;//这些是干别的事用的不用看 SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE); final String lastIP = sp.getString("IP", "none"); if(! lastIP.equals("none") ) { the_app.ip = lastIP; editText.setText(lastIP); } final Editor editor = sp.edit(); handler = new Handler()//handler是这么用的 { public void handleMessage(Message msg) { String words = (String)msg.obj; if( words.equals("ok") == true ) { Toast.makeText(LoginActivity.this, "来自服务器的问候:登陆成功!!欢迎使用~",Toast.LENGTH_LONG).show(); finish(); } else if(words.equals("did not login") ) { Toast.makeText(LoginActivity.this,"ip输错了或者是主机没有开", Toast.LENGTH_SHORT).show(); } } }; btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { the_app.ip = editText.getText().toString(); if(! lastIP.equals(the_app.ip)) { editor.putString("IP",the_app.ip); editor.commit(); } getThread = new GetThread();//点击按钮,发起线程 new Thread(getThread).start(); } }); } }
总的来看,过程就是这样的:
1)用户点击按钮,发起网络线程;
2)run函数进入,socket连接;
3)连接正常的话,收数据,
4)告诉handler更新UI。
有时候我们可能希望和服务器进行交互,下面是一个例子:
public void run() { try { PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) , true); // 用PrintWriter包装一下输出流 out.println("1 "+ nowFrom +" "+ nowTo);//这样就可以向socket输出 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//刚才用Scanner,用BufferedReader也行 String ans = in.readLine(); if(ans != null)//有时候会读进来null,我也不知道怎么回事,总之这个判断可以帮你的程序变得更健壮 { <span style="white-space:pre"> </span>Message msg = new Message(); msg.obj = ans; AskInputActivity.this.handler.sendMessage(msg); } } catch (IOException e) { Message msg = new Message(); msg.obj = "net error"; AskInputActivity.this.handler.sendMessage(msg); } } }
服务器端就是典型的java/c++网络编程,跟这篇文章要讨论的就没关系了。
一点经验是网络线程能不一直跑着就不要一直跑着,如果是严格的“请求-响应”工作模式的话,最好每次要发起连接的时候发起一个网络线程,发完-收完数据就结束,不然想结束一个线程不是那么轻松的事情。
最后,想正常利用网络,你需要在manifest里面申请网络权限:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <uses-permission android:name="android.permission.INTERNET" /> //这一句 <application android:name="com.zero.client.THUClient" android:allowBackup="true" android:icon="@drawable/icon_mod" android:label="@string/app_name" android:theme="@style/AppTheme" > …………一定要有,不然上面的写了等于白写,而且可恶的是他不告诉你……
暂且先记录这么多吧……
相关文章推荐
- Android网络开发之Socket通信
- Android网络开发之Socket通信
- 【Android应用开发技术:网络通信】Socket套接字
- android开发之socket通信 向PC机发信息 获取本机IP
- Android网络编程之Socket通信
- android开发之socket通信 向PC机发信息
- TCP通信 android,java语言开发ServerSocketActivity
- android手机开发——网络与通信
- Android网络编程实践之旅(二):基于Socket的网络通信
- [Android开发常见问题-20] Android 网络通信框架Volley简介(Google IO 2013)
- Android开发入门之网络通信(资源客户端)
- UDP通信(android开发java语言写的)DatagramSocket
- Android开发之socket通信 向PC机发信息 获取本机IP
- Android开发之Socket通信
- android开发之socket通信 向PC机发信息 获取本机IP
- Android开发入门之网络通信(通过HTTP协议实现文件上传)
- Android Socket网络通信
- android中的网络通信(一) socket编程
- Android Socket网络通信
- Android网络编程实践之旅(二):基于Socket的网络通信