Android聊天工具基于socket實現(xiàn)
特簡單, 沒有數(shù)據(jù)庫, 還沒有處理各種異常。
登錄:輸入用戶名點擊的登錄即可。
發(fā)送消息: 特定格式->toUser:message
1. 服務(wù)器:保存在線用戶
public class Online { private static Online mOnline = null; private LinkedHashMap<String, Socket> mOnlines = new LinkedHashMap<String, Socket>(); private Online() { } public synchronized static Online getInstance() { if(null == mOnline) { mOnline = new Online(); } return mOnline; } public void put(String key, Socket socket) { if(!mOnlines.containsKey(key)) { mOnlines.put(key, socket); } } public Socket get(String key) { return mOnlines.get(key); } public void remove(String key) { mOnlines.remove(key); } }
2. 服務(wù)器:一個簡單的socket服務(wù)器
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; // login:uid // send:fromuser:touser:message // logout:uid public class Server implements Runnable { private Socket mSocket; private Online mOnline; public Server(Socket socket) { mSocket = socket; mOnline = Online.getInstance(); } @Override public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader( mSocket.getInputStream())); String cmd = reader.readLine(); // login if (cmd.startsWith("login")) { String userName = cmd.split(":")[1]; mOnline.put(userName, mSocket); System.out.println(userName + " login..."); PrintWriter writer = new PrintWriter(mSocket.getOutputStream()); writer.println("success"); writer.flush(); } else if (cmd.startsWith("send")) { System.out.println(cmd); String[] cmds = cmd.split(":"); String from = cmds[1]; Socket to = mOnline.get(cmds[2]); String msg = cmds[3]; PrintWriter writer = new PrintWriter(to.getOutputStream()); System.out.println("rec:" + from + ":" + cmds[2] + ":" + msg); writer.println("rec:" + from + ":" + cmds[2] + ":" + msg); writer.flush(); }else if (cmd.startsWith("logout")) { System.out.println(cmd); String user = cmd.split(":")[1]; mOnline.get(user).close(); mOnline.remove(user); PrintWriter writer = new PrintWriter(mSocket.getOutputStream()); writer.println("success"); writer.flush(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8888); boolean flag = true; while (flag) { new Thread(new Server(server.accept())).start(); System.out.println("user in..."); } server.close(); } }
3. 客戶端登錄界面
public class MainActivity extends Activity { private EditText mUser; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mUser = (EditText) findViewById(R.id.username); } public void login(View view) { final String userName = mUser.getText().toString().trim(); Login login = new Login(userName); login.setOnLoginListener(new Login.LoginCallback() { @Override public void onLogin(boolean success) { if(success) { Intent intent = new Intent(MainActivity.this, Chat.class); intent.putExtra("user", userName); startActivity(intent); finish(); }else { Toast.makeText(MainActivity.this, "登錄失敗", Toast.LENGTH_SHORT).show(); } } }); login.login(); } }
4. 處理登錄
public class Login { private String mUserName; private LoginCallback mCallback; public Login(String userName) { mUserName = userName; } public void setOnLoginListener(LoginCallback callback) { mCallback = callback; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case Constant.SUCCESS: mCallback.onLogin(true); break; case Constant.FAILED: mCallback.onLogin(false); break; } }; }; public void login() { new Thread(new Runnable() { @Override public void run() { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("login:" + mUserName); writer.flush(); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); System.out.println(line); if("success".equals(line)) { PConnection.socket = socket; mHandler.sendEmptyMessage(Constant.SUCCESS); }else { mHandler.sendEmptyMessage(Constant.FAILED); } }catch(Exception e) { e.printStackTrace(); } } }).start(); } public interface LoginCallback { public void onLogin(boolean success); } }
5. 聊天界面
public class Chat extends Activity { private String mUserName; private EditText mEdit; private ListView mMessage; private ReceiverMessage mRecMessage; private SendMessage mSendMesage; private List<Map<String, String>> mData = new ArrayList<Map<String, String>>(); private MessagesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.chat_layout); mUserName = getIntent().getStringExtra("user"); mEdit = (EditText) findViewById(R.id.edit); mMessage = (ListView) findViewById(R.id.message); mRecMessage = new ReceiverMessage(); mRecMessage.setOnReceiverListener(new RecListener()); mRecMessage.run(); mSendMesage = new SendMessage(); mSendMesage.setOnSendListener(new SendListener()); mAdapter = new MessagesAdapter(this, mData); mMessage.setAdapter(mAdapter); } public void send(View view) { String[] content = mEdit.getText().toString().trim().split(":"); mSendMesage.send(mUserName, content[0], content[1]); } private class RecListener implements ReceiverMessage.OnReceiverListener { @Override public void onReceiver(String user, String msg) { Map<String, String> temp = new HashMap<String, String>(); temp.put("user", user); temp.put("msg", msg); temp.put("pos", "right"); mData.add(temp); mAdapter.notifyDataSetChanged(); } } private class SendListener implements SendMessage.OnSendListener { @Override public void onSend(String[] msg) { Map<String, String> temp = new HashMap<String, String>(); temp.put("user", "我"); temp.put("msg", msg[1]); temp.put("pos", "left"); mData.add(temp); mAdapter.notifyDataSetChanged(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { if(R.id.logout == item.getItemId()) { Logout logout = new Logout(); logout.setOnLogoutListener(new Logout.OnLogoutListener() { @Override public void onLogout(boolean success) { if(success) { Toast.makeText(Chat.this, "注銷成功", Toast.LENGTH_SHORT).show(); finish(); }else { Toast.makeText(Chat.this, "注銷失敗", Toast.LENGTH_SHORT).show(); } } }); logout.logout(mUserName); } return super.onOptionsItemSelected(item); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } }
6. 發(fā)送消息
public class SendMessage { private OnSendListener mListener; public void setOnSendListener(OnSendListener listener) { mListener = listener; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { mListener.onSend((String[]) msg.obj); }; }; // send:from:to:message public void send(final String from , final String to, final String msg) { new Thread(new Runnable() { @Override public void run() { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("send:" + from + ":" + to + ":" + msg); writer.flush(); Message message = mHandler.obtainMessage( Constant.SUCCESS, new String[] {to, msg}); message.sendToTarget(); } catch(Exception e) { } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } public interface OnSendListener { public void onSend(String[] msg); } }
7. 接收消息,死循環(huán),但阻塞,沒啥問題
public class ReceiverMessage { private OnReceiverListener mListener; public void setOnReceiverListener(OnReceiverListener listener) { mListener = listener; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { String[] cmds = (String[]) msg.obj; mListener.onReceiver(cmds[0], cmds[1]); }; }; public void run() { new Thread(new Runnable() { @Override public void run() { try { Socket socket = PConnection.socket; while(true) { System.out.println("wait for message..."); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); if(line.startsWith("rec")) { //rec:fromuser:touser:message String[] cmds = line.split(":"); System.out.println(cmds[0] + ":" + cmds[1] + ":" + cmds[2] + ":" + cmds[3]); Message msg = mHandler.obtainMessage(Constant.SUCCESS, new String[] {cmds[1], cmds[3]}); msg.sendToTarget(); } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } public interface OnReceiverListener { public void onReceiver(String user, String msg); } }
8. 注銷登錄
public class Logout { public OnLogoutListener mListener; public void setOnLogoutListener(OnLogoutListener listner) { mListener = listner; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if(Constant.SUCCESS == msg.what) { mListener.onLogout(true); }else { mListener.onLogout(false); } }; }; public void logout(final String user) { new Thread(new Runnable() { @Override public void run() { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("logout:" + user); writer.flush(); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); if("success".equals(reader.readLine())) { PConnection.socket = null; mHandler.sendEmptyMessage(Constant.SUCCESS); }else { mHandler.sendEmptyMessage(Constant.FAILED); } } catch (Exception e) { e.printStackTrace(); } } }).start(); } public interface OnLogoutListener { public void onLogout(boolean success); } }
9. 存放登錄后的socket,在發(fā)送消息和接收消息時使用該socket
public class PConnection { public static Socket socket; }
希望本文所述對大家學(xué)習(xí)有所幫助。
相關(guān)文章
Android 中 MD5 的幾種生成方式(小結(jié))
這篇文章主要介紹了Android 中 MD5 的幾種生成方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Kotlin使用協(xié)程實現(xiàn)高效并發(fā)程序流程詳解
這篇文章主要介紹了Kotlin使用協(xié)程實現(xiàn)高效并發(fā)程序流程,協(xié)程屬于Kotlin中非常有特色的一項技術(shù),因為大部分編程語言中是沒有協(xié)程這個概念的。那么什么是協(xié)程呢?它其實和線程有點相似,可以簡單地將它理解成一種輕量級的線程2023-01-01Flutter應(yīng)用框架搭建實現(xiàn)屏幕適配方案詳解
移動設(shè)備多樣性,特別是Android的碎片化嚴重,存在各種各樣的分辨率,flutter跨平臺開發(fā)又需要同時支持Android和IOS,為盡可能的還原設(shè)計圖效果提升用戶的體驗,根據(jù)設(shè)計稿設(shè)計屏幕ui的時候我們需要考慮到屏幕適配的問題2022-11-11