天天看點

android 4.0網絡程式設計之socket聊天室

這一段時間一直在學習android網絡程式設計這塊的内容,由于android3 .0以上不能夠在UI線程中通路網絡;這裡拿android4.0網絡程式設計詳解這本書中socket程式設計的聊天室執行個體,進行修改使之能夠運作在android4.0平台上,以記錄作為解決android3.0以上平台不能在UI線程中通路網絡的一種方法,當然這種方法也是從網絡當中借鑒過來的。

這個方法主要是在onCreate()方法中加入以下代碼:

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()

                .detectDiskWrites().detectNetwork().penaltyLog().build());

        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()

                .penaltyLog().penaltyDeath().build());

下面就貼出整個聊天室執行個體的代碼:

(1).伺服器部分主要包括Broadcast.java,ClientThread.java,Server.java,ServerThread.java這幾個代碼部分;

Broadcast.java:

package com.jacky.server.internet;

import java.io.IOException;

public class BroadCast extends Thread {
	
	ClientThread clientThread;
	ServerThread serverThread;
	String str;
	
	public BroadCast(ServerThread serverThread)
	{
		this.serverThread=serverThread;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				Thread.sleep(200);
			}
			catch(InterruptedException E){}
			
			synchronized(serverThread.messages)
			{
				if(serverThread.messages.isEmpty())
				{
					continue;
				}
				str=(String)this.serverThread.messages.firstElement();
			}
			synchronized(serverThread.clients)
			{
				for(int i=0;i<serverThread.clients.size();i++)
				{
					clientThread=(ClientThread)serverThread.clients.elementAt(i);
					try
					{
						clientThread.out.writeUTF(str);
					}
					catch(IOException E){}
				}
				this.serverThread.messages.removeElement(str);
			}
		}
		
	}

}
           

ClientThread.java:

package com.jacky.server.internet;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ClientThread extends Thread{
	
	Socket clientSocket;
	
	DataInputStream in=null;
	DataOutputStream out=null;
	
	ServerThread serverThread;
	String str;
	
	public static int ConnectNumber=0;
	
	public ClientThread(Socket socket,ServerThread serverThread)
	{
		clientSocket=socket;
		this.serverThread=serverThread;
		try
		{
			in=new DataInputStream(clientSocket.getInputStream());
			out=new DataOutputStream(clientSocket.getOutputStream());
		}
		catch(IOException e2)
		{
			System.out.println("發生異常"+e2);
			System.out.println("建立I/O通道失敗");
			System.exit(3);
		}
	}
	public void run()
	{
		while(true)
		{
			try
			{
				String message=in.readUTF();
				synchronized(serverThread.messages)
				{
					if(message!=null)
					{
						serverThread.messages.addElement(message);
						Server.jTextAreal.append( message+'\n');
					}
				}
			}catch(IOException E){break;}
		}
	}

}
           

Server.java:

package com.jacky.server.internet;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Server extends JFrame implements ActionListener {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -4000885328679526739L;
	BorderLayout borderLayout1=new BorderLayout();
	BorderLayout borderLayout2=new BorderLayout();
	
	JPanel jPanel1=new JPanel();
	JPanel jPanel2=new JPanel();
	
	JButton jButton1=new JButton();
	JButton jButton2=new JButton();
	
	JScrollPane jScrollPanel=new JScrollPane();
	
	
	static JTextArea jTextAreal=new JTextArea();
	boolean bool=false,start=false;
	
	ServerThread serverThread;
	Thread thread;
	
	public Server()
	{
		super("Server");
		
		getContentPane().setLayout(borderLayout1);
		
		jButton1.setText("啟動伺服器");
		jButton1.addActionListener(this);
		jButton2.setText("關閉伺服器");
		jButton2.addActionListener(this);
		
		this.getContentPane().add(jPanel1,java.awt.BorderLayout.NORTH);
		jPanel1.add(jButton1);
		jPanel1.add(jButton2);
		
		jTextAreal.setText("");
		jPanel2.setLayout(borderLayout2);
		jPanel2.add(jScrollPanel,java.awt.BorderLayout.CENTER);
		jScrollPanel.getViewport().add(jTextAreal);
		this.getContentPane().add(jPanel2,java.awt.BorderLayout.CENTER);
		
		this.setSize(400,400);
		this.setVisible(true);
		
	}
	public static void main(String[] args)
	{
		Server server=new Server();
		server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	

	public void actionPerformed(ActionEvent e)
	{
		if(e.getSource()==jButton1)
		{
			serverThread=new ServerThread();
			serverThread.start();
		}else if(e.getSource()==jButton2){
			bool=false;
			start=false;
			serverThread.finalize();
			this.setVisible(false);
		}
	}
}
           

ServerClient.java:

package com.jacky.server.internet;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Vector;

public class ServerThread extends Thread{
	
	ServerSocket serverSocket;
	
	public static final int PORT=8521;
	
	Vector<ClientThread>clients;
	Vector<Object>messages;
	
	BroadCast broadcast;
	
	String ip;
	InetAddress myIPaddress=null;
	
	public ServerThread()
	{
		clients=new Vector<ClientThread>();
		messages=new Vector<Object>();
		
		try
		{
			serverSocket=new ServerSocket(PORT);
		}catch(IOException E){}
		
		try{
			myIPaddress=InetAddress.getLocalHost();
		}catch(UnknownHostException e)
		{
			System.out.println(e.toString());
		}
		ip=myIPaddress.getHostAddress();
		Server.jTextAreal.append("伺服器位址:"+ip+"端口号:"+
		String.valueOf(serverSocket.getLocalPort())+"\n");
		broadcast=new BroadCast(this);
		broadcast.start();
	}

	public void run()
	{
		while(true)
		{
			try
			{
				Socket socket=serverSocket.accept();
				System.out.println(socket.getInetAddress().getHostAddress());
				ClientThread clientThread=new ClientThread(socket,this);
				clientThread.start();
				if(socket!=null)
				{
					synchronized(clients)
					{
						clients.addElement(clientThread);
					}
				}
			}catch(IOException E)
			{
				System.out.println("發生異常:"+E);
				System.out.println("建立用戶端聯機失敗!");
				System.exit(2);
			}
		}
	}
	
	public void finalize()
	{
		try
		{
			serverSocket.close();
		}
		catch(IOException E){}
		serverSocket=null;
	}
}
           

(2).android 用戶端部分:

ChatClientActivity.java:

package com.example.chatandroidclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.sql.Date;
import java.text.SimpleDateFormat;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ChatClientActivity extends Activity implements Runnable{

	private EditText usernameEdit;
	private EditText ipEdit;
	private EditText historyEdit;
	private EditText messageEdit;
	
	private Button loginButton;
	private Button sendButton;
	private Button leaveButton;
	
	private String username,ip,chat_txt,chat_in;
	
	public static final int PORT=8521;
	
	Socket socket;
	
	Thread thread;
	//建立一個資料輸入流對象
	DataInputStream in;
	//建立一個資料輸出流對象
	DataOutputStream out;
	
	boolean flag=false;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		/*由于android3.0以上不能夠在主線程中經行網絡通路,是以在此處加上這一段代碼*/
		StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()
                .detectDiskWrites().detectNetwork().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()
                .penaltyLog().penaltyDeath().build());
        /*由于android3.0以上不能夠在主線程中經行網絡通路,是以在此處加上這一段代碼*/
		setContentView(R.layout.main);
		usernameEdit=(EditText)findViewById(R.id.username);
		ipEdit=(EditText)findViewById(R.id.ip);
		historyEdit=(EditText)findViewById(R.id.history);
		messageEdit=(EditText)findViewById(R.id.message);
		
		loginButton=(Button)findViewById(R.id.LoginButton);
		sendButton=(Button)findViewById(R.id.SendButton);
		leaveButton=(Button)findViewById(R.id.LeaveButton);
		
		loginButton.setOnClickListener(listener);
		sendButton.setOnClickListener(listener);
		leaveButton.setOnClickListener(listener);
	}
	View.OnClickListener listener=new View.OnClickListener()
	{
		public void onClick(View v)
		{
			switch(v.getId())
			{
			case R.id.LoginButton:
				if(flag==true){
					Toast.makeText(ChatClientActivity.this, "已經登入!!!", Toast.LENGTH_SHORT).show();
					return;
				}
				username=usernameEdit.getText().toString();
				ip=ipEdit.getText().toString();
				if(username!=""&&username!=null&&username!="使用者名輸入"&&ip!=null){
					try
					{
						socket=new Socket(ip,PORT);
						in=new DataInputStream(socket.getInputStream());
						out=new DataOutputStream(socket.getOutputStream());
						Date now=new Date(System.currentTimeMillis());
						SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss");
						String nowStr=format.format(now);
						out.writeUTF("$$"+username+" "+nowStr+"上線了!");
					}catch(IOException el)
					{
						System.out.println("can not connect!!");
					}
					thread=new Thread(ChatClientActivity.this);
					thread.start();
					flag=true;
				}
				break;
			case R.id.SendButton:
				if(flag==false)
				{
					Toast.makeText(ChatClientActivity.this,"沒有登入,請登入!!",Toast.LENGTH_SHORT).show();
					return;
				}
				chat_txt=messageEdit.getText().toString();
				if(chat_txt!=null)
				{
					Date now=new Date(System.currentTimeMillis());
					SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss");
					String nowStr=format.format(now);
					
					try
					{
						out.writeUTF("^_^"+username+" "+nowStr+"說\n"+chat_txt);
						messageEdit.setText(" ");//清空發送框中的内容
					}catch(IOException e2){}
				}
				else
				{
					try{out.writeUTF("請說話");}
					catch(IOException e3){}
				}
				break;
			case R.id.LeaveButton:
				if(flag==true)
				{
					if(flag==false){
						Toast.makeText(ChatClientActivity.this, "沒有登入,請登入!!",Toast.LENGTH_SHORT).show();
						return;
					}
					try
					{
						out.writeUTF("=="+username+"下線了!");
						out.close();
						in.close();
						socket.close();
					}catch(IOException e4){}
				}
				flag=false;
				Toast.makeText(ChatClientActivity.this, "已退出!", Toast.LENGTH_SHORT).show();
				break;
			}
			
		}
	};
	
	public void run(){
		while(true)
		{
			try
			{
				chat_in=in.readUTF();
				chat_in=chat_in+"\n";
				mHandler.sendMessage(mHandler.obtainMessage());
			}catch(IOException e){}
		}
	}
	Handler mHandler=new Handler()
	{
		public void handleMessage(Message msg)
		{
			historyEdit.append(chat_in);
			super.handleMessage(msg);
		}
	};
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.chat_client, 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);
	}
}
           

main.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:orientation="vertical" >

    <TextView
        android:id="@+id/usernameText"
        android:layout_width="70dp"
        android:layout_height="40dp"
        android:text="@string/username" />

    <EditText
        android:id="@+id/username"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:layout_toRightOf="@id/usernameText"
        android:hint="@null"
        android:maxLength="10"
        android:text=" ">
    </EditText>

    <Button
        android:id="@+id/LoginButton"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_toRightOf="@id/username"
        android:text="@string/login" />

    <TextView
        android:id="@+id/ipText"
        android:layout_width="70dp"
        android:layout_height="40dp"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/username"
        android:text="@string/ip" />

    <EditText
        android:id="@+id/ip"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:layout_alignTop="@id/ipText"
        android:layout_toRightOf="@id/ipText"
        android:digits=".1234567890"
        android:hint="@null"
        android:text="192.168.1.108" >       
    </EditText>
    <Button
        android:id="@+id/LeaveButton"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_alignTop="@id/ip"
        android:layout_toRightOf="@id/ip"
        android:text="@string/leave" />

    <EditText
        android:id="@+id/history"
        android:layout_width="fill_parent"
        android:layout_height="280dp"
        android:hint="@null"
        android:layout_below="@id/ipText"
        android:inputType="none"
        android:gravity="top" >
    </EditText>

    <EditText
        android:id="@+id/message"
        android:layout_width="280dp"
        android:layout_height="240dp"
        android:hint="@null"
        android:layout_below="@id/history"
        android:gravity="top" >
    </EditText>

    <Button
        android:id="@+id/SendButton"
        android:layout_width="wrap_content"
        android:layout_height="240dp"
        android:layout_alignTop="@id/message"
        android:layout_toRightOf="@id/message"
        android:text="@string/send" />

</RelativeLayout>
           
android 4.0網絡程式設計之socket聊天室
android 4.0網絡程式設計之socket聊天室

繼續閱讀