Android Design: Intentservice вызывает приложение не отвечает - PullRequest
2 голосов
/ 18 апреля 2019

Я разработал код, который приводит к тому, что приложение не отвечает.

  1. Я использовал okhttp3.WebSocket для непрерывного входного потока данных, для которого я решил запустить IntentService, который будет получать данные с сервера.

  2. У меня есть IntentService; в onHandleIntent я даю сервисный вызов для получения данных с сервера (примерно 3 вызова).

  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);
}

1 Ответ

0 голосов
/ 18 апреля 2019

Возможно, вы захотите проверить, что блокирует основной поток на более чем 6 секунд.

Обычно ANR происходит, когда основной поток блокируется в течение некоторого времени.6-10 секунд.

...