Android聊天工具基于socket實(shí)現(xiàn)
特簡(jiǎn)單, 沒(méi)有數(shù)據(jù)庫(kù), 還沒(méi)有處理各種異常。
登錄:輸入用戶名點(diǎn)擊的登錄即可。
發(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ù)器:一個(gè)簡(jiǎn)單的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, "注銷(xiāo)成功", Toast.LENGTH_SHORT).show();
finish();
}else {
Toast.makeText(Chat.this, "注銷(xiāo)失敗", 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),但阻塞,沒(méi)啥問(wè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. 注銷(xiāo)登錄
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ā)送消息和接收消息時(shí)使用該socket
public class PConnection {
public static Socket socket;
}
希望本文所述對(duì)大家學(xué)習(xí)有所幫助。
相關(guān)文章
Android 中 MD5 的幾種生成方式(小結(jié))
這篇文章主要介紹了Android 中 MD5 的幾種生成方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android實(shí)現(xiàn)支付寶AR掃描動(dòng)畫(huà)效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)支付寶AR掃描動(dòng)畫(huà)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02
Android利用貝塞爾曲線繪制動(dòng)畫(huà)的示例代碼
本篇就借由動(dòng)畫(huà)驅(qū)動(dòng)貝塞爾曲線繪制看看動(dòng)起來(lái)的貝塞爾曲線什么效果。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-05-05
Android實(shí)現(xiàn)登錄注冊(cè)頁(yè)面(上)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)登錄注冊(cè)頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Android實(shí)現(xiàn)生成二維碼并保存到相冊(cè)
這篇文章主要介紹了如何利用Android實(shí)現(xiàn)二維碼的生成,并且保存到本地相冊(cè)。文中的示例代碼講解詳細(xì),感興趣的小伙伴快跟隨小編學(xué)習(xí)一下2022-04-04
Kotlin使用協(xié)程實(shí)現(xiàn)高效并發(fā)程序流程詳解
這篇文章主要介紹了Kotlin使用協(xié)程實(shí)現(xiàn)高效并發(fā)程序流程,協(xié)程屬于Kotlin中非常有特色的一項(xiàng)技術(shù),因?yàn)榇蟛糠志幊陶Z(yǔ)言中是沒(méi)有協(xié)程這個(gè)概念的。那么什么是協(xié)程呢?它其實(shí)和線程有點(diǎn)相似,可以簡(jiǎn)單地將它理解成一種輕量級(jí)的線程2023-01-01
Flutter應(yīng)用框架搭建實(shí)現(xiàn)屏幕適配方案詳解
移動(dòng)設(shè)備多樣性,特別是Android的碎片化嚴(yán)重,存在各種各樣的分辨率,flutter跨平臺(tái)開(kāi)發(fā)又需要同時(shí)支持Android和IOS,為盡可能的還原設(shè)計(jì)圖效果提升用戶的體驗(yàn),根據(jù)設(shè)計(jì)稿設(shè)計(jì)屏幕ui的時(shí)候我們需要考慮到屏幕適配的問(wèn)題2022-11-11

