編輯:關於Android編程
網上已經有很多利用socket實現聊天的例子了,但是我看過很多,多多少有一些問題存在。
這裡我將實現一個比較完整的聊天例子,並解釋其中的邏輯。
由於socket這一塊比較大,所以我將分出幾篇來寫一個比較完整的socket例子。
這裡我們先來實現一個最簡單的,服務器與客戶端通訊,實現消息推送的功能。
目的:服務器與客戶端建立連接,客戶端可以向服務器發送消息,服務器可以向客戶端推送消息。
1,SocketUrls 確定ip地址和端口號
public class SocketUrls{ // ip地址 public final static String IP = "192.168.1.110"; // 端口號 public final static int PORT = 8888; }
2,Main 程序的入口
public class Main { public static void main(String[] args) throws Exception { new ChatServer().initServer(); } }
3,Bean 實體類
用戶信息 UserInfoBean
public class UserInfoBean implements Serializable { private static final long serialVersionUID = 1L; private long userId;// 用戶id private String userName;// 用戶名 private String likeName;// 昵稱 private String userPwd;// 用戶密碼 private String userIcon;// 用戶頭像 //省略get/set方法 }
聊天信息 MessageBean
public class MessageBean extends UserInfoBean { private long messageId;// 消息id private long groupId;// 群id private boolean isGoup;// 是否是群消息 private int chatType;// 消息類型;1,文本;2,圖片;3,小視頻;4,文件;5,地理位置;6,語音;7,視頻通話 private String content;// 文本消息內容 private String errorMsg;// 錯誤信息 private int errorCode;// 錯誤代碼 //省略get/set方法 }
4,ChatServer 聊天服務,最主要的程序
public class ChatServer { // socket服務 private static ServerSocket server; public Gson gson = new Gson(); /** * 初始化socket服務 */ public void initServer() { try { // 創建一個ServerSocket在端口8080監聽客戶請求 server = new ServerSocket(SocketUrls.PORT); createMessage(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 創建消息管理,一直接收消息 */ private void createMessage() { try { System.out.println("等待用戶接入 : "); // 使用accept()阻塞等待客戶請求 Socket socket = server.accept(); System.out.println("用戶接入 : " + socket.getPort()); // 開啟一個子線程來等待另外的socket加入 new Thread(new Runnable() { public void run() { createMessage(); } }).start(); // 向客戶端發送信息 OutputStream output = socket.getOutputStream(); // 從客戶端獲取信息 BufferedReader bff = new BufferedReader(new InputStreamReader(socket.getInputStream())); // Scanner scanner = new Scanner(socket.getInputStream()); new Thread(new Runnable() { public void run() { try { String buffer; while (true) { // 從控制台輸入 BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); buffer = strin.readLine(); // 因為readLine以換行符為結束點所以,結尾加入換行 buffer += "\n"; output.write(buffer.getBytes("utf-8")); // 發送數據 output.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); // 讀取發來服務器信息 String line = null; // 循環一直接收當前socket發來的消息 while (true) { Thread.sleep(500); // System.out.println("內容 : " + bff.readLine()); // 獲取客戶端的信息 while ((line = bff.readLine()) != null) { MessageBean messageBean = gson.fromJson(line, MessageBean.class); System.out.println("用戶 : " + messageBean.getUserName()); System.out.println("內容 : " + messageBean.getContent()); } } // server.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("錯誤 : " + e.getMessage()); } } }
1,appliaction 實例化一個全局的聊天服務
public class ChatAppliaction extends Application { public static ChatServer chatServer; public static UserInfoBean userInfoBean; @Override public void onCreate() { super.onCreate(); } }
2,ip地址和端口號和服務器保持一致
3,聊天實力類同服務器端一樣
4,xml布局。登陸,聊天
1,登錄
2,聊天
5,LoginActivity 登陸
public class LoginActivity extends AppCompatActivity { private EditText chat_name_text, chat_pwd_text; private Button chat_login_btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); chat_name_text = (EditText) findViewById(R.id.chat_name_text); chat_pwd_text = (EditText) findViewById(R.id.chat_pwd_text); chat_login_btn = (Button) findViewById(R.id.chat_login_btn); chat_login_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (getLogin(chat_name_text.getText().toString().trim(), chat_pwd_text.getText().toString().trim())) { getChatServer(); Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } } }); } private boolean getLogin(String name, String pwd) { if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) return false; if (name.equals("admin") && pwd.equals("123123123a")) return true; return false; } private void getChatServer() { ChatAppliaction.chatServer = new ChatServer(); } }
6,MainActivity 聊天
public class MainActivity extends AppCompatActivity { private LinearLayout chat_ly; private TextView left_text, right_view; private EditText chat_et; private Button send_btn; private ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); chat_ly = (LinearLayout) findViewById(R.id.chat_ly); chat_et = (EditText) findViewById(R.id.chat_et); send_btn = (Button) findViewById(R.id.send_btn); send_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ChatAppliaction.chatServer.sendMessage(chat_et.getText().toString().trim()); chat_ly.addView(initRightView(chat_et.getText().toString().trim())); } }); //添加消息接收隊列 ChatAppliaction.chatServer.setChatHandler(new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { //發送回來消息後,更新ui chat_ly.addView(initLeftView(msg.obj.toString())); } } }); } /**靠右的消息 * @param messageContent * @return */ private View initRightView(String messageContent) { right_view = new TextView(this); right_view.setLayoutParams(layoutParams); right_view.setGravity(View.FOCUS_RIGHT); right_view.setText(messageContent); return right_view; } /**靠左的消息 * @param messageContent * @return */ private View initLeftView(String messageContent) { left_text = new TextView(this); left_text.setLayoutParams(layoutParams); left_text.setGravity(View.FOCUS_LEFT); left_text.setText(messageContent); return left_text; } }
7,ChatServer 聊天邏輯,最主要的
public class ChatServer { private Socket socket; private Handler handler; private MessageBean messageBean; private Gson gson = new Gson(); // 由Socket對象得到輸出流,並構造PrintWriter對象 PrintWriter printWriter; InputStream input; OutputStream output; DataOutputStream dataOutputStream; public ChatServer() { initMessage(); initChatServer(); } /** * 消息隊列,用於傳遞消息 * * @param handler */ public void setChatHandler(Handler handler) { this.handler = handler; } private void initChatServer() { //開個線程接收消息 receiveMessage(); } /** * 初始化用戶信息 */ private void initMessage() { messageBean = new MessageBean(); messageBean.setUserId(1); messageBean.setMessageId(1); messageBean.setChatType(1); messageBean.setUserName("admin"); ChatAppliaction.userInfoBean = messageBean; } /** * 發送消息 * * @param contentMsg */ public void sendMessage(String contentMsg) { try { if (socket == null) { Message message = handler.obtainMessage(); message.what = 1; message.obj = "服務器已經關閉"; handler.sendMessage(message); return; } byte[] str = contentMsg.getBytes("utf-8");//將內容轉utf-8 String aaa = new String(str); messageBean.setContent(aaa); String messageJson = gson.toJson(messageBean); /** * 因為服務器那邊的readLine()為阻塞讀取 * 如果它讀取不到換行符或者輸出流結束就會一直阻塞在那裡 * 所以在json消息最後加上換行符,用於告訴服務器,消息已經發送完畢了 * */ messageJson += "\n"; output.write(messageJson.getBytes("utf-8"));// 換行打印 output.flush(); // 刷新輸出流,使Server馬上收到該字符串 } catch (Exception e) { e.printStackTrace(); Log.e("test", "錯誤:" + e.toString()); } } /** * 接收消息,在子線程中 */ private void receiveMessage() { new Thread(new Runnable() { @Override public void run() { try { // 向本機的8080端口發出客戶請求 socket = new Socket(SocketUrls.IP, SocketUrls.PORT); // 由Socket對象得到輸入流,並構造相應的BufferedReader對象 printWriter = new PrintWriter(socket.getOutputStream()); input = socket.getInputStream(); output = socket.getOutputStream(); dataOutputStream = new DataOutputStream(socket.getOutputStream()); // 從客戶端獲取信息 BufferedReader bff = new BufferedReader(new InputStreamReader(input)); // 讀取發來服務器信息 String line; while (true) { Thread.sleep(500); // 獲取客戶端的信息 while ((line = bff.readLine()) != null) { Log.i("socket", "內容 : " + line); Message message = handler.obtainMessage(); message.obj = line; message.what = 1; handler.sendMessage(message); } if (socket == null) break; } output.close();//關閉Socket輸出流 input.close();//關閉Socket輸入流 socket.close();//關閉Socket } catch (Exception e) { e.printStackTrace(); Log.e("test", "錯誤:" + e.toString()); } } }).start(); } }
寫到這裡,已經完成了所有的代碼。
這個demo可以實現手機端向服務器發送消息,服務器向手機端發送消息。
這個demo可以算是推送功能,不過真正的推送沒有這麼簡單。作為一個socket的入門了解,可以從中看到socket編程的思想。
思想很重要。
這次寫的是:手機端和服務器之間的通訊
後面我會陸續寫出:
1,客戶端和客戶端聊天
2,群聊
3,發送地理位置
4,圖文混排
5,發送文件(圖片,小視頻,語音)
本文實例講解了通知Notification使用方法,此知識點就是用作通知的顯示,包括振動、燈光、聲音等效果,分享給大家供大家參考,具體內容如下效果圖:MainActivi
PopupWindow簡介PopupWindow是懸浮在當前activity上的一個容器,用它可以展示任意的內容。PopupWindow跟位置有關的API有下面幾個:sh
先給大家展示效果圖:package com.example.walkerlogin1; import android.app.Activity; import andro
Android開發中,我們常使用到ListView視圖,下面介紹ListView的幾種使用方法。 主界面首先,在主界面上添加幾個按鈕,用於界面跳轉。界面布局:&