修改在android sdk 在低版本中一个兼容问题

This commit is contained in:
远方夕阳 2019-06-03 14:25:03 +08:00
parent 27a7c5d2c0
commit 18e7464051
8 changed files with 216 additions and 308 deletions

View File

@ -19,7 +19,7 @@
<entry file="file://$PROJECT_DIR$/pom.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="836">
<caret line="44" column="67" selection-start-line="44" selection-start-column="67" selection-end-line="44" selection-end-column="67" />
<caret line="44" column="66" selection-start-line="44" selection-start-column="66" selection-end-line="44" selection-end-column="66" />
</state>
</provider>
</entry>
@ -36,7 +36,7 @@
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/CIMConfig.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="171">
<state relative-caret-position="172">
<caret line="57" column="78" selection-start-line="57" selection-start-column="78" selection-end-line="57" selection-end-column="78" />
<folding>
<element signature="imports" expanded="true" />
@ -80,7 +80,7 @@
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="1">
<component name="ProjectFrameBounds">
<option name="y" value="23" />
<option name="width" value="1920" />
<option name="height" value="1057" />
@ -90,7 +90,6 @@
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="PackagesPane" />
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
@ -143,6 +142,7 @@
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
</panes>
</component>
<component name="PropertiesComponent">
@ -218,16 +218,18 @@
<workItem from="1559009816995" duration="1293000" />
<workItem from="1559110709907" duration="1801000" />
<workItem from="1559198165156" duration="1213000" />
<workItem from="1559269742769" duration="598000" />
</task>
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="7630000" />
<option name="totallyTimeSpent" value="8228000" />
</component>
<component name="ToolWindowManager">
<frame x="0" y="23" width="1920" height="1057" extended-state="1" />
<frame x="0" y="23" width="1920" height="1057" extended-state="0" />
<editor active="true" />
<layout>
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.271123" />
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.27433154" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info id="Designer" order="2" />
<window_info id="UI Designer" order="3" />
@ -235,7 +237,7 @@
<window_info id="Web" order="5" side_tool="true" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info active="true" anchor="bottom" id="Run" order="2" visible="true" weight="0.51953536" />
<window_info anchor="bottom" id="Run" order="2" weight="0.51953536" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.26821542" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
@ -317,7 +319,7 @@
<entry file="file://$PROJECT_DIR$/pom.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="836">
<caret line="44" column="67" selection-start-line="44" selection-start-column="67" selection-end-line="44" selection-end-column="67" />
<caret line="44" column="66" selection-start-line="44" selection-start-column="66" selection-end-line="44" selection-end-column="66" />
</state>
</provider>
</entry>
@ -337,7 +339,7 @@
</entry>
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/CIMConfig.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="171">
<state relative-caret-position="172">
<caret line="57" column="78" selection-start-line="57" selection-start-column="78" selection-end-line="57" selection-end-column="78" />
<folding>
<element signature="imports" expanded="true" />

View File

@ -24,7 +24,6 @@ package com.farsunset.cim.sdk.android;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
@ -33,24 +32,25 @@ import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import com.farsunset.cim.sdk.android.coder.CIMLogger;
import com.farsunset.cim.sdk.android.coder.ClientMessageDecoder;
import com.farsunset.cim.sdk.android.coder.ClientMessageEncoder;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.exception.SessionClosedException;
import com.farsunset.cim.sdk.android.model.HeartbeatRequest;
import com.farsunset.cim.sdk.android.model.HeartbeatResponse;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.Protobufable;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
@ -60,7 +60,7 @@ import android.os.Process;
*
* @author 3979434@qq.com
*/
class CIMConnectorManager {
class CIMConnectorManager{
private static CIMConnectorManager manager;
@ -79,6 +79,9 @@ class CIMConnectorManager {
private static final HandlerThread IDLE_HANDLER_THREAD = new HandlerThread("READ-IDLE", Process.THREAD_PRIORITY_BACKGROUND);
private LinkedBlockingQueue<Protobufable> sendFailBodyQueue = new LinkedBlockingQueue<Protobufable>();
private final ReentrantLock IOLOCK = new ReentrantLock();
private Selector selector;
private SocketChannel socketChannel ;
private Context context;
@ -106,10 +109,10 @@ class CIMConnectorManager {
if(socketChannel == null || !socketChannel.isOpen()) {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.setOption(StandardSocketOptions.SO_RCVBUF,READ_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, WRITE_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY,true);
socketChannel.socket().setTcpNoDelay(true);
socketChannel.socket().setKeepAlive(true);
socketChannel.socket().setReceiveBufferSize(READ_BUFFER_SIZE);
socketChannel.socket().setSendBufferSize(WRITE_BUFFER_SIZE);
}
if(selector == null || !selector.isOpen()) {
@ -135,7 +138,9 @@ class CIMConnectorManager {
public void connect(final String host, final int port) {
if (!isNetworkConnected(context)) {
boolean isNetworkConnected = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetwork() != null;
if (!isNetworkConnected) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
@ -145,8 +150,7 @@ class CIMConnectorManager {
return;
}
boolean isConnected = isConnected();
if (CONNECTING_FLAG.get() || isConnected) {
if (CONNECTING_FLAG.get() || isConnected()) {
return;
}
@ -160,6 +164,8 @@ class CIMConnectorManager {
@Override
public void run() {
IOLOCK.lock();
LOGGER.startConnect(host, port);
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
@ -179,6 +185,7 @@ class CIMConnectorManager {
for(SelectionKey key : selector.selectedKeys()){
if((key.interestOps() & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT && socketChannel.finishConnect()) {
IOLOCK.unlock();
handelConnectedEvent();
continue;
}
@ -199,8 +206,161 @@ class CIMConnectorManager {
}
});
}
public void destroy() {
closeSession();
closeSelector();
}
public void closeSession() {
try {
socketChannel.close();
} catch (IOException ignore) {
}finally {
this.sessionClosed();
}
}
public boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public void send(final Protobufable body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
int result = 0;
try {
IOLOCK.lock();
ByteBuffer buffer = messageEncoder.encode(body);
while(buffer.hasRemaining()){
result += socketChannel.write(buffer);
}
} catch (IOException e) {
result = -1;
}finally {
IOLOCK.unlock();
if(result <= 0) {
sendFailBodyQueue.offer(body);
closeSession();
}else {
messageSent(body);
}
}
}
});
}
private void sendFaildQueueBody() {
Protobufable body = sendFailBodyQueue.poll();
if(body == null) {
return;
}
send(body);
sendFaildQueueBody();
}
private void sessionCreated() {
LOGGER.sessionCreated(socketChannel);
LAST_READ_TIME.set(System.currentTimeMillis());
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_SUCCESSED);
context.sendBroadcast(intent);
sendFaildQueueBody();
}
private void sessionClosed() {
idleHandler.removeMessages(0);
LAST_READ_TIME.set(0);
LOGGER.sessionClosed(socketChannel);
readBuffer.clear();
if(readBuffer.capacity() > READ_BUFFER_SIZE) {
readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
}
closeSelector();
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
context.sendBroadcast(intent);
}
private void sessionIdle() {
LOGGER.sessionIdle(socketChannel);
/**
* 用于解决wifi情况下偶而路由器与服务器断开连接时客户端并没及时收到关闭事件 导致这样的情况下当前连接无效也不会重连的问题
*
*/
if (System.currentTimeMillis() - LAST_READ_TIME.get() >= CONNECT_ALIVE_TIME_OUT) {
closeSession();
}
}
private void messageReceived(Object obj) {
if (obj instanceof Message) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
intent.putExtra(Message.class.getName(), (Message) obj);
context.sendBroadcast(intent);
}
if (obj instanceof ReplyBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
intent.putExtra(ReplyBody.class.getName(), (ReplyBody) obj);
context.sendBroadcast(intent);
}
}
private void messageSent(Object message) {
LOGGER.messageSent(socketChannel, message);
if (message instanceof SentBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_SUCCESSED);
intent.putExtra(SentBody.class.getName(), (SentBody) message);
context.sendBroadcast(intent);
}
}
private Handler idleHandler = new Handler(IDLE_HANDLER_THREAD.getLooper()) {
public void handleMessage(android.os.Message m) {
sessionIdle();
@ -239,12 +399,6 @@ class CIMConnectorManager {
private void handelSocketReadEvent() throws IOException {
LAST_READ_TIME.set(System.currentTimeMillis());
idleHandler.removeMessages(0);
idleHandler.sendEmptyMessageDelayed(0, READ_IDLE_TIME);
int result = 0;
while((result = socketChannel.read(readBuffer)) > 0) {
@ -257,6 +411,10 @@ class CIMConnectorManager {
closeSession();
return;
}
markLastReadTime();
readBuffer.position(0);
@ -266,6 +424,8 @@ class CIMConnectorManager {
return;
}
LOGGER.messageReceived(socketChannel,message);
if(isHeartbeatRequest(message)) {
@ -288,190 +448,30 @@ class CIMConnectorManager {
readBuffer.clear();
readBuffer = newBuffer;
}
private void markLastReadTime() {
LAST_READ_TIME.set(System.currentTimeMillis());
idleHandler.removeMessages(0);
idleHandler.sendEmptyMessageDelayed(0, READ_IDLE_TIME);
}
public void send(final SentBody body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
boolean isSuccessed = false;
String exceptionName = SessionClosedException.class.getSimpleName();
if (isConnected()) {
try {
ByteBuffer buffer = messageEncoder.encode(body);
int result = 0;
while(buffer.hasRemaining()){
result += socketChannel.write(buffer);
}
isSuccessed = result > 0;
} catch (IOException e) {
exceptionName = e.getClass().getSimpleName();
closeSession();
}
}
if (!isSuccessed) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_FAILED);
intent.putExtra(Exception.class.getName(), exceptionName);
intent.putExtra(SentBody.class.getName(), body);
context.sendBroadcast(intent);
}else {
messageSent(body);
}
}
});
}
public void send(final HeartbeatResponse body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
try {
socketChannel.write(messageEncoder.encode(body));
messageSent(body);
} catch (IOException ignore) {
closeSession();
}
}
});
}
public void sessionCreated() {
LOGGER.sessionCreated(socketChannel);
LAST_READ_TIME.set(System.currentTimeMillis());
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_SUCCESSED);
context.sendBroadcast(intent);
}
public void sessionClosed() {
idleHandler.removeMessages(0);
LAST_READ_TIME.set(0);
LOGGER.sessionClosed(socketChannel);
readBuffer.clear();
if(readBuffer.capacity() > READ_BUFFER_SIZE) {
readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
}
closeSelector();
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
context.sendBroadcast(intent);
}
public void sessionIdle() {
LOGGER.sessionIdle(socketChannel);
/**
* 用于解决wifi情况下偶而路由器与服务器断开连接时客户端并没及时收到关闭事件 导致这样的情况下当前连接无效也不会重连的问题
*
*/
if (System.currentTimeMillis() - LAST_READ_TIME.get() >= CONNECT_ALIVE_TIME_OUT) {
closeSession();
}
}
public void messageReceived(Object obj) {
if (obj instanceof Message) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
intent.putExtra(Message.class.getName(), (Message) obj);
context.sendBroadcast(intent);
}
if (obj instanceof ReplyBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
intent.putExtra(ReplyBody.class.getName(), (ReplyBody) obj);
context.sendBroadcast(intent);
}
}
public void messageSent(Object message) {
LOGGER.messageSent(socketChannel, message);
if (message instanceof SentBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_SUCCESSED);
intent.putExtra(SentBody.class.getName(), (SentBody) message);
context.sendBroadcast(intent);
}
}
public static boolean isNetworkConnected(Context context) {
try {
ConnectivityManager nw = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = nw.getActiveNetworkInfo();
return networkInfo != null;
} catch (Exception ignore) {
}
return false;
}
public HeartbeatResponse getHeartbeatResponse() {
private HeartbeatResponse getHeartbeatResponse() {
return HeartbeatResponse.getInstance();
}
public boolean isHeartbeatRequest(Object data) {
private boolean isHeartbeatRequest(Object data) {
return data instanceof HeartbeatRequest;
}
public void destroy() {
closeSession();
closeSelector();
}
public boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public void closeSession() {
try {
socketChannel.close();
} catch (IOException ignore) {
}finally {
this.sessionClosed();
}
}
public void closeSelector() {
private void closeSelector() {
try {
selector.close();
} catch (IOException ignore) {}

View File

@ -22,7 +22,6 @@
package com.farsunset.cim.sdk.android;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.exception.SessionClosedException;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
@ -102,15 +101,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED)) {
onReplyReceived((ReplyBody) intent.getSerializableExtra(ReplyBody.class.getName()));
}
/*
* 获取sendbody发送失败事件
*/
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_SENT_FAILED)) {
String exceptionName = intent.getStringExtra(Exception.class.getName());
SentBody sentBody = (SentBody) intent.getSerializableExtra(SentBody.class.getName());
onSentFailed(exceptionName, sentBody);
}
/*
* 获取sendbody发送成功事件
@ -142,7 +133,9 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
private void onInnerConnectionClosed() {
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
if (CIMConnectorManager.isNetworkConnected(context)) {
boolean isNetworkConnected = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetwork() != null;
if (isNetworkConnected) {
CIMPushManager.connect(context, 0);
}
@ -150,8 +143,9 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
}
private void onConnectionFailed(long reinterval) {
boolean isNetworkConnected = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetwork() != null;
if (CIMConnectorManager.isNetworkConnected(context)) {
if (isNetworkConnected) {
onConnectionFailed();
CIMPushManager.connect(context, reinterval);
@ -185,18 +179,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
private boolean isForceOfflineMessage(String action) {
return CIMConstant.MessageAction.ACTION_999.equals(action);
}
private void onSentFailed(String exceptionName, SentBody body) {
// 与服务端端开链接重新连接
if (SessionClosedException.class.getSimpleName().equals(exceptionName)) {
CIMPushManager.connect(context, 0);
} else {
// 发送失败 重新发送
CIMPushManager.sendRequest(context, body);
}
}
public abstract void onMessageReceived(com.farsunset.cim.sdk.android.model.Message message, Intent intent);

View File

@ -117,16 +117,16 @@ public class CIMLogger {
builder.append("id:").append(session.hashCode());
try {
if (session.getLocalAddress() != null) {
builder.append(" L:").append(session.getLocalAddress().toString());
if (session.socket().getLocalAddress() != null) {
builder.append(" L:").append(session.socket().getLocalAddress().toString());
}
} catch (Exception ignore) {
}
try {
if (session.getRemoteAddress() != null) {
builder.append(" R:").append(session.getRemoteAddress().toString());
if (session.socket().getRemoteSocketAddress() != null) {
builder.append(" R:").append(session.socket().getRemoteSocketAddress().toString());
}
} catch (Exception ignore) {
}

View File

@ -74,9 +74,6 @@ public interface CIMConstant {
// 消息广播action
String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.MESSAGE_RECEIVED";
// 发送sendbody失败广播
String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED";
// 发送sendbody成功广播
String ACTION_SENT_SUCCESSED = "com.farsunset.cim.SENT_SUCCESSED";

View File

@ -1,37 +0,0 @@
/**
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************************
* *
* Website : http://www.farsunset.com *
* *
***************************************************************************************
*/
package com.farsunset.cim.sdk.android.exception;
import java.io.Serializable;
public class NetworkDisabledException extends Exception implements Serializable {
private static final long serialVersionUID = 1L;
public NetworkDisabledException() {
super();
}
public NetworkDisabledException(String s) {
super(s);
}
}

View File

@ -1,37 +0,0 @@
/**
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************************
* *
* Website : http://www.farsunset.com *
* *
***************************************************************************************
*/
package com.farsunset.cim.sdk.android.exception;
import java.io.Serializable;
public class SessionClosedException extends Exception implements Serializable {
private static final long serialVersionUID = 1L;
public SessionClosedException() {
super();
}
public SessionClosedException(String s) {
super(s);
}
}