实现此功能需要考虑的几点:
1)如何保证Socket长连接一直存在并有效运行
2)通过Service运行Socket,当服务端有数据时,通过广播或者handler来更新UI
具体效果,来上代码:
@Override
public void run() {
try {
loginService();
} catch (IOException ex) {
ex.printStackTrace();
isConnected = false;
sendStatus("Socket连接失败!");
send("Socket连接失败!");
}
int i = 0;
while (true) {
if (stopService) {
return;
}
try {
if (isConnected && socket != null && socket.isConnected()) {
try {
socket.sendUrgentData(0xFF);// 发送检测socket连接包
} catch (Exception ex) {
sendStatus("Socket连接已断开!");
isConnected = false;
}
if (isConnected && !socket.isInputShutdown()) {
String data = in.readLine();// 线程阻塞接受完毕后向下执行
if (Utils.isAppOnForeground(mContext)) {
Intent intent = new Intent("GET_ROMETE_DATA");
intent.putExtra("msg", data);
mContext.sendBroadcast(intent);
} else {
// 发送通知
send(data);
// 将数据缓存起来
Utils.writeSDFile(mContext.getFilesDir()
+ Utils.CACHEDIR, data + "-----time:"
+ Utils.getTime() + "\n");
}
}
} else {
i++;
loginService();
}
} catch (Exception e) {
sendStatus("Socket连接失败!");
e.printStackTrace();
} finally {
if (!isConnected && i == 3) {
i = 0;
try {
Thread.sleep((long) ((Math.random() * 300) * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}// 当前线程休眠随机分钟之内休眠之后再次登錄
} else {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
连接Socket代码:
// 这里获得本地配置的ip和端口
String host = (String) PushSharePerfance.getInstance(mContext)
.getValue(PushSharePerfance.LOGIN_HOST, "String");
int port = (Integer) PushSharePerfance.getInstance(mContext).getValue(
PushSharePerfance.LOGIN_PORT, "Integer");
if (TextUtils.isEmpty(host) || port == 0) {
socket = new Socket(HOST, PORT);
} else if (!TextUtils.isEmpty(host) && port != 0) {
socket = new Socket(host, port);
}
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
String data = "{\"cmd\":\"connect\",\"userId\":\"123\"}";
if (socket.isConnected()) {
if (!socket.isOutputShutdown()) {
out.print(data);
out.flush();
isConnected = true;
Log.d(TAG, "-------" + data + "-----send login----");
sendStatus("Socket连接成功!");
}
}
// 通过系统闹钟来维持长连接心跳
private void keepConnect() {
// 创建Intent对象,action为ELITOR_CLOCK
Intent heartbeatIntent = new Intent("ELITOR_CLOCK");
Intent intent = new Intent(this, SocketService.class);
// 定义一个PendingIntent对象,PendingIntent.getBroadcast包含了sendBroadcast的动作。
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
PendingIntent beatIntent = PendingIntent.getBroadcast(this, 0,
heartbeatIntent, 0);
// AlarmManager对象,注意这里并不是new一个对象,Alarmmanager为系统级服务
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
// 设置闹钟从当前时间开始,每隔5s执行一次PendingIntent对象pi,注意第一个参数与第二个参数的关系
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
30 * 1000, pi);
// am.setRepeating(AlarmManager.RTC_WAKEUP,
// System.currentTimeMillis() + 60 * 1000, 60 * 1000, beatIntent);
}
如此,一个通过Socket长连接的方式可以模拟一个在线推送的功能