Я разработал код, который приводит к тому, что приложение не отвечает.
Я использовал okhttp3.WebSocket для непрерывного входного потока данных, для которого я решил запустить IntentService, который будет получать данные с сервера.
У меня есть IntentService; в onHandleIntent я даю сервисный вызов для получения данных с сервера (примерно 3 вызова).
Для вызова службы я использую AsyncTask для Android, внутри которого мой класс WebConnectionManger работает в другом потоке.
Внутри веб-сокета я получаю информацию о конкретной записи, для которой я собираюсь получить информацию из сервисного вызова.
Для 5-6 таких записей мое приложение работает нормально, но если записи получают 80-100, мое приложение не отвечает вообще, и я получаю ANR.
Я использую простой простой TCP-запрос для этого.
Может кто-нибудь скажет мне, что является реальной проблемой и как я могу от нее избавиться?
любая помощь приветствуется.
Я вставляю код WebSocket, AsyncTask (остальные два имеют одинаковую реализацию), класс WebConnectionManger и класс IntentService.
WebSocket.class
public class WebSocket {
public static boolean isConnected;
public static String TO_UPDATE = "toOrderUpdate";
@SuppressLint("StaticFieldLeak")
private static WebSocket _instance;
private static OkHttpClient client;
private static WebSocket webSocket = null;
private Context mContext;
private AppPreferences preferences;
private WebSocket() {
client = new OkHttpClient();
}
public WebSocket(Context context) {
client = new OkHttpClient();
mContext = context;
preferences = new AppPreferences(mContext);
init(mContext);
}
public static WebSocket getInstance(Context mContext) {
if (_instance == null) {
_instance = new WebSocket(mContext);
}
return _instance;
}
public static void closeWebSocket() {
if (isConnected) {
webSocket.close(1001, LOGOUT);
_instance = null;
webSocket = null;
isConnected = false;
}
}
public void init(Context context) {
if (webSocket == null) {
preferences = new AppPreferences(context);
Request request = new Request.Builder()
.url(preferences.getWSUrl() + ":" + preferences.getWSPort() + "/" + preferences.getUserID())
.build();
WebSocketMessageListener messageListener = new WebSocketMessageListener();
webSocket = client.newWebSocket(request, messageListener);
isConnected = true;
}
}
private class WebSocketMessageListener extends WebSocketListener {
// private static final int NORMAL_CLOSURE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
Log.i("******", "Socket Open");
}
@Override
public void onMessage(WebSocket webSocket, String response) {
try {
super.onMessage(webSocket, response);
Log.i("******", "Message Received " + response);
// Logger.log("OnMessage : " + response);
ModelAdvertisements modelAdvertisements = DecoderJSONWebSocket.decode(response);
Intent intentForService = new Intent(mContext, WebSocketService.class);
int transCode = Integer.parseInt(modelAdvertisements.getTC());
Intent mwBroadcastIntent = new Intent();
switch (transCode) {
case 1005:
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_LOGICAL_SESSION_START_END);
mContext.sendBroadcast(mwBroadcastIntent);
break;
case 1004:
case 1006:
case 1007:
intentForService.putExtra(TO_UPDATE, true);
mContext.startService(intentForService);
break;
case 1008:
try {
mwBroadcastIntent.putExtra(KEY_AUCTION_FLOOR_SNAPSHOT, modelAdvertisements);
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_MARKET_DATASNAPSHOT);
mContext.sendBroadcast(mwBroadcastIntent);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
} catch (Exception e) {
// e.printStackTrace();
}
}
@Override
public void onClosing(WebSocket webSockett, int code, String reason) {
super.onClosing(webSockett, code, reason);
Log.i("******", "Socket Closing Reason: " + reason);
}
@Override
public void onClosed(WebSocket webSockett, int code, String reason) {
super.onClosed(webSockett, code, reason);
Log.i("******", "Socket closed reason: " + reason);
webSocket = null;
isConnected = false;
}
@Override
public void onFailure(WebSocket webSockett, Throwable t, Response response) {
super.onFailure(webSockett, t, response);
isConnected = false;
webSocket = null;
Logger.log(e);
}
}
}
WebSocketService.class
public class WebSocketService extends IntentService {
String securityId;
private Context mContext;
private String tokenId;
private String contractCode;
private int transCode;
private boolean toUpdate;
private String mktCode;
public WebSocketService() {
super("WebSocketService");
}
public WebSocketService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent != null) {
tokenId = intent.getStringExtra(KEY_TOKEN_ID);
transCode = intent.getIntExtra(KEY_TRANSCODE, 0);
toUpdate = intent.getBooleanExtra(NeMLWebSocket.TO_UPDATE, false);
contractCode = intent.getStringExtra(KEY_SYMBOL);
mktCode = intent.getStringExtra(KEY_ADV_REF_ID);
}
securityId = DatabaseUtils.getSecurityIdFromFOOrders(mContext, tokenId);
performTokenMasterTask();
}
@Override
public void onCreate() {
super.onCreate();
mContext = this;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
protected void performTokenMasterTask() {
synchronized (this) {
TokenMasterTask tokenMasterTask = new TokenMasterTask(mContext, new RequestCallback() {
@Override
public void onStart() {
}
@Override
public void onComplete(Object object) {
if (transCode == TC_1004_WEB_SOCKET) {
Intent mwBroadcastIntent = new Intent();
mwBroadcastIntent.setAction(Constants.IntentKeys.KEY_TOKEN_SESSION_START_END);
mContext.sendBroadcast(mwBroadcastIntent);
// stopSelf();
} else if (transCode == TC_TIME_WEB_SOCKET || transCode == TC_AUCTION_WEB_SOCKET) {
performTimeSessionTask();
}
}
@Override
public void onProgress(int current, int total) {
}
@Override
public void onError(int transCode, String msg) {
try {
Logger.log(transCode + "--->" + msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}, mktCode);
tokenMasterTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, tokenId);
if (transCode == TC_TIME_WEB_SOCKET || transCode == TC_AUCTION_WEB_SOCKET) {
performTimeSessionTask();
}
}
}
public void performTimeSessionTask() {
synchronized (this) {
TimeSessionMapTask timeSessionMapTask = new TimeSessionMapTask(mContext, new RequestCallback() {
ProgressDialog progressDialog;
private boolean m_ConnectionErr = false;
@Override
public void onStart() {
}
@Override
public void onComplete(Object object) {
if (!m_ConnectionErr) {
if (transCode == TC_AUCTION_WEB_SOCKET) {
performFoOrderTask();
}
}
}
@Override
public void onProgress(int current, int total) {
}
@Override
public void onError(int transCode, String msg) {
try {
Logger.log("Received ErrorMessage :" + msg + " \n ErrorCode :" + transCode);
} catch (Exception e) {
e.printStackTrace();
}
}
}, modelMarket);
timeSessionMapTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, TIME_SESSION);
if (transCode == TC_AUCTION_WEB_SOCKET) {
performFoOrderTask();
}
}
}
private synchronized void performFoOrderTask() {
synchronized (mContext) {
FOOrdersTask foOrdersTask = new FOOrdersTask(mContext, new RequestCallback() {
@Override
public void onStart() {
}
@Override
public void onComplete(Object object) {
}
@Override
public void onProgress(int current, int total) {
}
@Override
public void onError(int transCode, String msg) {
}
});
foOrdersTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, tokenId);
}
}
}
TokenMasterTask.class
public class TokenMasterTask extends AsyncTask<Object, Void, ModelToken> {
private final String mktCode;
private RequestCallback _callback;
@SuppressLint("StaticFieldLeak")
private Context context;
private boolean isConnectionError;
private ModelToken modelToken;
private boolean isServerDown;
public TokenMasterTask(Context context, RequestCallback requestCallback, String mktCode) {
this.context = context;
this.mktCode = mktCode;
if (requestCallback == null) {
requestCallback = new RequestCallback() {
@Override
public void onStart() {
}
@Override
public void onComplete(Object object) {
}
@Override
public void onProgress(int current, int total) {
}
@Override
public void onError(int transCode, String msg) {
}
};
}
this._callback = requestCallback;
}
@Override
protected ModelToken doInBackground(Object... voids) {
if (voids != null && voids.length > 0) {
String tokenId = String.valueOf(voids[0]);
isConnectionError = false;
transactionCall(tokenId);
}
return modelToken;
}
private void transactionCall(String tokenId) {
try {
WebConnectionManager connectionManager = new WebConnectionManager(context, new ConnectionListener() {
@Override
public void notifyReadCompleted(String f_Response) {
modelToken = DecoderTokenRequest.decode(f_Response);
synchronized (TokenMasterTask.this) {
TokenMasterTask.this.notify();
}
}
@Override
public void notifySocketError(boolean isServerDown) {
if (!isServerDown) {
isConnectionError = true;
}
TokenMasterTask.this.isServerDown = isServerDown;
synchronized (TokenMasterTask.this) {
TokenMasterTask.this.notify();
}
}
@Override
public void onReceivePacket(int total, int current) {
_callback.onProgress(current, total);
}
});
connectionManager.modifiedHandleRequest(EncoderTokenRequest.encode(context, tokenId,mktCode).getBytes());
} catch (Exception e) {
e.printStackTrace();
Logger.log(e);
}
synchronized( TokenMasterTask.this) {
try {
TokenMasterTask.this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void onPostExecute(ModelToken modelToken) {
if (isServerDown) {
_callback.onError(Constants.ErrorCode.TC_ERROR_SERVER_DOWN, "");
} else if (isConnectionError) {
_callback.onError(0, "Connection Error.");
} else if (modelToken!=null && modelToken.getErrorCode() != null && !TextUtils.isEmpty(modelToken.getErrorCode()) && !modelToken.getErrorCode().equalsIgnoreCase("200")) {
_callback.onError(Integer.parseInt(modelToken.getErrorCode()), modelToken.getError());
} else {
_callback.onComplete(modelToken);
}
super.onPostExecute(modelToken);
}
}
WebConnectionManager.class
public class WebConnectionManager {
private String m_Response = "";
byte[] m_RequestData;
boolean m_Read_Response_Completed = false;
Thread l_WorkerThread;
ConnectionListener m_ConnectionListener;
boolean m_IsFetchCompleted;
Context context;
AppPreferences preferences;
Socket mWebSocket;
public WebConnectionManager(Context mcontext, ConnectionListener f_LoginListener) {
m_ConnectionListener = f_LoginListener;
m_IsFetchCompleted = false;
context = mcontext;
preferences = new AppPreferences(context);
}
public String modifiedHandleRequest(byte[] f_RequestData) {
m_RequestData = f_RequestData;
Logger.log("" + Constants.TIME_OUT);
l_WorkerThread = new Thread(new Runnable() {
@Override
public void run() {
String encodedIP = null;
try {
if (mWebSocket == null || !mWebSocket.isBound()
|| mWebSocket.isClosed() ) {
mWebSocket = new Socket(ip, port);
mWebSocket.setKeepAlive(true);
mWebSocket.setSoTimeout(Constants.TIME_OUT);
}
if (m_RequestData == null) {
m_Read_Response_Completed = true;
if (!mWebSocket.isClosed()) {
m_ConnectionListener.notifyReadCompleted("Connected");
return;
} else {
m_ConnectionListener.notifyReadCompleted("Disconnected");
return;
}
} else {
String request = new String(m_RequestData);
Logger.log(Utils.encodePackets(request));
}
InputStream inputStream = mWebSocket.getInputStream();
try {
mWebSocket.getOutputStream().write(m_RequestData);
} catch (Exception e) {
Logger.log(e);
}
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream(1048576);
byte[] buffer = new byte[1048576];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
m_Response = byteArrayOutputStream.toString();
}
inputStream.close();
byteArrayOutputStream.close();
mWebSocket.close();
if (TextUtils.isEmpty(m_Response.toString().trim())) {
throw new IOException("Empty Response");
} else {
m_ConnectionListener.notifyReadCompleted(m_Response.toString());
}
} catch (UnknownHostException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
} catch (SocketTimeoutException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(false);
mWebSocket = null;
e.printStackTrace();
} catch (SocketException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
} catch (IOException e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
} catch (Exception e) {
Logger.log(e);
m_ConnectionListener.notifySocketError(true);
mWebSocket = null;
e.printStackTrace();
}
}
});
l_WorkerThread.start();
return m_Response;
}
}
И интерфейсы.
public interface ConnectionListener {
void notifyReadCompleted(String f_Response);
void notifySocketError(boolean isServerDown);
void onReceivePacket(int total, int current);
}
public interface RequestCallback {
void onStart();
void onComplete(Object object);
void onProgress(int current, int total);
void onError(int transCode, String msg);
}