andoid 4 以上的编程一个和之前版本最大的不同就是不能在主线程中做网络链接,即是不能在主activity中建立socket链接。socket链接要在新建的线程中建立,信息的传递如果需在控件中显示,通过Handler类来改变控件UI。
贴出服务端的代码
public class MyServer {
public static ArrayList<Socket> socketList=new ArrayList<Socket>();
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InetAddress addr = InetAddress.getLocalHost();
String ip=addr.getHostAddress().toString();//获得本机IP
String address=addr.getHostName().toString();//获得本机名称
//查看服务器ip信息
ServerSocket ss=new ServerSocket(30000);
System.out.println(ip+" "+address+" "+ss.getLocalPort());
//进行监听
while(true){
Socket s=ss.accept();
//该信息输出说明服务器监听到有客户端传输到服务器的信息
System.out.println("there is massage send to server");
socketList.add(s);
new Thread(new ServerThread(s)).start();
}
}
}
服务端线程
public class ServerThread implements Runnable {
Socket s=null;
BufferedReader br=null;
InputStreamReader inp=null;
public ServerThread(Socket s) throws IOException{
this.s=s;
br=new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8"));
inp=new InputStreamReader(s.getInputStream(),"utf-8");
}
@Override
public void run() {
// TODO Auto-generated method stub
//测试进入servverThread
System.out.println("ServerThread start");
try{
String content=null;
System.out.println("ServerThread start in the try block");
while((content=readFromClient())!=null){
//查看客户端传输到服务器的信息
System.out.println(content);
for(Socket s:MyServer.socketList){
OutputStream os=s.getOutputStream();
os.write((content+"\n").getBytes("utf-8"));
}
}
}catch(Exception e){
e.printStackTrace();
}
}
private String readFromClient(){
try{
return br.readLine();
}catch(IOException e){
MyServer.socketList.remove(s);
}
return null;
}
}
服务端的代码的主要功能是接受来自客户端的信息,再将接受到的信息,发送给所有链接上服务器的客户端。
下面是客户端的代码
public class MainActivity extends ActionBarActivity {
EditText input,show;
Button send;
Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
send=(Button) findViewById(R.id.send);
show=(EditText) findViewById(R.id.show);
input=(EditText)findViewById(R.id.input);
handler=new Handler(){
public void handleMessage(Message msg){
if(msg.what==0x1233){
show.append("\n"+msg.obj.toString());
}
}
};
try{
new Thread(new ClientThread(handler,send,input)).start();
}catch(Exception e){
e.printStackTrace();
}
}
@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;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
客户端主线程主要是获取界面的按钮有两个EditText
子线程代码
public class ClientThread implements Runnable{
private Socket s;
private Handler handler=null;
BufferedReader br=null;
OutputStream out;
Button send;
EditText input;
public ClientThread(Handler handler,Button send,EditText input) throws IOException{
this.handler=handler;
this.send=send;
this.input=input;
}
@Override
public void run() {
// TODO Auto-generated method stub
//在子线程中建立网络连接
try{
s=new Socket("192.168.1.101",30000);
}catch(Exception e){
e.printStackTrace();
}
send.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//获取输出流,输出input输入框中的信息
try {
out=s.getOutputStream();
out.write((input.getText().toString()+"\n").getBytes("utf-8"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
try {
br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String content=null;
while((content=br.readLine())!=null){
Message mes=new Message();
mes.what=0x1233;
mes.obj=content;
//在子线程中通过handler改变主线程中的ui
handler.sendMessage(mes);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在子线程中建立socket链接,发送信息,接受来自服务器的信息,通过handler将信息显示在界面上。
在AndroidManifest.xml 中加上链接网络的权限
<uses-permission android:name="android.permission.INTERNET" ></uses-permission>