在android中遇到的陷阱异常socket问题抢沙发

2013-12-11    分类:Android开发Java开发原创文章编程相关      

由于剧情需要,老师在期末的时候给我们java布置了课程设计,是设计一个C/S架构的傻逼查表的员工工资增删改查客户端。基于win平台的java程序基本已经死掉了。为了笨鸟先飞,决定用Android写客户端,服务端还是在win平台上运行。
先来了解下Socket编程,Socket的入门其实并不难,但深入android的Socket后会出现各种各样的奇葩问题,有些陷阱就算是百度也是解决不了的。
背景回顾:

我自己在minVersion=4.2的环境下写socket会报错,比如:android.os.NetworkOnMainThreadException异常

 

还有很多在运行时的错误就不呈现出来了。
但这时我又找不到问题所在,于是网上随便找了个源码,网上找的源码是minVersion=2.2。我发现网上的源码跟我的写法大同小异,偏偏他的能运行我的运行不了。
一怒之下试着在4.2的源码中把socket放进一个Thread的构造方法中,发现也不行。但是2.2的源码在Thread的构造方法中是可以运行的,这就造成了一个极大的陷阱疑问!
说到多线程,要调用socket其实还有很多方法,于是把socket放如run方法中,在构造函数中start()。这时奇迹出现了,程序居然能跑了,而且通信也正常了。后来在谷歌翻阅了下官方文档,2.2在向上兼容的时候对网络多线程做了一些限制。
简单的说就是,在4.0以后的版本用socket的话务必要让socket放入一个线程中跑动,在主线程中运行socket会报错。而2.3之前的socket在主线程中跑是没问题的。
根据很多程序员的开发经验中得到的提示就是无论在哪一个版本最好都让它独立出一个线程跑就行了。

 

 

 

 

注意:
1、android在使用网络服务的时候务必记得一定要申请权限,之前刚上手安卓的时候老是忘记,总之百度来百度去百度不出个所以然。
     网络服务的权限xml代码:  <uses-permission android:name="android.permission.INTERNET" />
2、Android 4.0以后的版本和2.0的使用方法有所不同,容易掉入陷阱。(像这样的问题书本和老师是教不了的,只能靠开发经验去摸索去研究)
图(环境是  4.2):




先来给出代码,服务端的代码(服务端网上随便找的,一找一大堆):

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPDesktopServer implements Runnable{
    public static final String SERVERIP = "127.0.0.1";
    public static final int SERVERPORT = 1818;
    public void run() {
         try {
             System.out.println("S: Connecting…");
             ServerSocket serverSocket = new ServerSocket(SERVERPORT);
             while (true) {
                  Socket client = serverSocket.accept();
                  System.out.println("S: Receiving…");
                  try {
                      BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                      String str = in.readLine();
                      System.out.println("S: Received: '" + str + "'");
                    } catch(Exception e) {
                        System.out.println("S: Error");
                        e.printStackTrace();
                    } finally {
                        client.close();
                        System.out.println("S: Done.");
                    }
             }
          } catch (Exception e) {
             System.out.println("S: Error");
             e.printStackTrace();
         }
    }
   public static void main (String a[]) {
        Thread desktopServerThread = new Thread(new TCPDesktopServer());
        desktopServerThread.start();
    }
}
安卓客户端的代码:
//MainActivity.java
package com.example.android_2013_12_11_final;
import android.os.Bundle;
import android.app.Activity;
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
    Button btn_connect;
    EditText et_mess;
    ClientConnect clientConnect;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_connect = (Button)findViewById(R.id.btn_connect);
        et_mess = (EditText)findViewById(R.id.textContent);
        btn_connect.setOnClickListener(new ButtonOnClick( this ));
    }
    private class ButtonOnClick implements View.OnClickListener{
        MainActivity ui;
        //创建构造函数将 MainActivity 传入监听类
        ButtonOnClick( MainActivity ui ){
            this.ui = ui;
        }
        //监听对象,点击时将ui传入ClientConnect类中
        @Override
        public void onClick(View v) {
            // TODO 自动生成的方法存根
            clientConnect = new ClientConnect( ui );
            Toast.makeText(getApplicationContext(), "111", 0).show();
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}
//  ClientConnect.java
package com.example.android_2013_12_11_final;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.util.Log;
import android.util.PrintWriterPrinter;
public class ClientConnect extends Thread{
    public Socket socket = null;
    public PrintWriter out;
    public BufferedReader in;
    public MainActivity ui;
    private String ip = "172.16.111.94";
    private int port = 1818 ;
    private String tag = "ClientConnect类";
    public ClientConnect( MainActivity ui ){
        this.ui = ui;
        Log.i(tag , "1111");
        ui.et_mess.append("aaa");
        start();
    }
    public void run(){
        try {
            Log.i(tag , "2222-111");
            socket = new Socket( ip ,  port );
            Log.i(tag , "2222-222");
            out = new PrintWriter(socket.getOutputStream(),true);
            out.println("连接成功");
            out.flush();
            Log.i(tag , "3333");
        } catch (UnknownHostException e) {
            // TODO 自动生成的 catch 块
            Log.i(tag , e.toString()+"  444");
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            Log.i(tag , e.toString()+"  555");
            e.printStackTrace();
        }
    }
}

转载请注明:乔布尸 » 在android中遇到的陷阱异常socket问题

继续查看有关 的文章

相关文章

我来说说

*

*

取消