Handler.postDelayed永远不会被触发(Java - Android)

时间:2018-02-16 16:55:05

标签: java android multithreading handler android-looper

我一直试图找到为什么我的处理程序根本没有触发事件,但我没有找到它的运气。我将发布整个班级,希望有人注意到一个愚蠢的错误或其他什么。

该类只管理一些套接字的生命周期(我这样做是因为Android设备在关闭它们后不久就重新打开端口时似乎非常情绪化)。这个类是一个单例,因为我想知道我到处使用什么端口。

package com.ltd.jeefo.alex.routeassistant.wifi.sync.utils;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.annotation.Nullable;

import com.ltd.jeefo.alex.routeassistant.logging.ILog;
import com.ltd.jeefo.alex.routeassistant.logging.ScopedLogger;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;

/**
 * Created by Alex on 16/02/18.
 */

public class SocketsManager {
    private static final SocketsManager ourInstance = new SocketsManager();
    private static final Handler handler = new Handler();

    public static SocketsManager getInstance() {
        return ourInstance;
    }

    @SuppressLint("UseSparseArrays")
    private static final HashMap<Integer, ManagedServerSocket> serverSockets = new HashMap<>();

    private SocketsManager() {
    }

    /**
     * Method used for obtaining the server socket for a given port
     * @param port the port where we want the socket to be opened
     * @return the server socket to be used or null if we couldn't start a server socket at that port
     */
    public ManagedServerSocket getSocketAtPort(final int port) {
        ManagedServerSocket managedServerSocket;
        if (serverSockets.containsKey(port)) {
            managedServerSocket = serverSockets.get(port);
        } else {
            managedServerSocket = new ManagedServerSocket(port, handler);
            serverSockets.put(port, managedServerSocket);
        }

        return managedServerSocket;
    }

    /**
     * Closes all the sockets after some delay
     *
     * @param msDelay the delay in milliseconds
     */
    public void closeAllSocketsAfterDelay(final long msDelay) {
        for (final ManagedServerSocket managedSocket : serverSockets.values()) {
            managedSocket.RequestSocketClosingAfterDelay(msDelay);
        }
    }

    enum ServerSocketStatus {
        OPEN_NOT_REQUESTED,
        OPEN_FAILED,
        OPENED, // there is always a close request started by default, just in case
        USER_CLOSE_REQUESTED,
        CLOSED
    }

    public class ManagedServerSocket {
        private final ILog logger;

        private final static long DEFAULT_CLOSING_TIME_MILLS = 3600000; // one hour
        private final static long DEFAULT_RETRY_TIME_MILLS = 15000; // 15 seconds
        private final Handler mHandler;
        private final int mPort;

        private ServerSocket mSocket;
        private SocketsManager.ServerSocketStatus serverSocketStatus;
        private Long closingTime;

        private Runnable defaultClosingRunnable;
        private Runnable explicitClosingRunnable;

        private ManagedServerSocket(final int port, final Handler handler) {
            this.mPort = port;
            this.mHandler = handler;
            logger = new ScopedLogger(null, ManagedServerSocket.class, "Port", Integer.toString(mPort));

            serverSocketStatus = SocketsManager.ServerSocketStatus.OPEN_NOT_REQUESTED;

            defaultClosingRunnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        logger.Warn("Server socket closing automatically at port %s after long delay",
                                Integer.toString(mPort));
                        mSocket.close();
                        serverSocketStatus = SocketsManager.ServerSocketStatus.CLOSED;
                        closingTime = new Date().getTime();
                    } catch (IOException e) {
                        e.printStackTrace();
                        logger.Error(e, "Failed to close server socket at port %s after delay", Integer.toString(mPort));
                    }
                }
            };

            explicitClosingRunnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        logger.Debug("Socket closing after delay");
                        mSocket.close();
                        serverSocketStatus = SocketsManager.ServerSocketStatus.CLOSED;
                        closingTime = new Date().getTime();
                    } catch (IOException e) {
                        e.printStackTrace();
                        logger.Error(e, "Failed to close server socket after delay");
                    }
                }
            };
        }

        public void RequestSocketClosingAfterDelay(long delayMills) {
            logger.Debug("Close socket after delay %s ms", Long.toString(delayMills));
            switch (serverSocketStatus) {
                case OPEN_NOT_REQUESTED:
                    logger.Warn("Closing port that was never opened");
                    return;
                case OPEN_FAILED:
                    logger.Error("Cannot close a socket that failed to open");
                    return;
                case CLOSED:
                    logger.Warn("Cannot request closing an already closed socket");
                    return;
                case OPENED:
                    mHandler.removeCallbacks(defaultClosingRunnable);
                    break;
                case USER_CLOSE_REQUESTED:
                    logger.Warn("Requested to close a socket that was already requested for closing");
                    mHandler.removeCallbacks(explicitClosingRunnable);
                    break;
            }

            mHandler.postDelayed(explicitClosingRunnable, delayMills);
            serverSocketStatus = SocketsManager.ServerSocketStatus.USER_CLOSE_REQUESTED;
        }

        @Nullable
        private ServerSocket RequestSocketForUsage() {
            boolean socketIsOpened = true;
            switch (serverSocketStatus) {
                case USER_CLOSE_REQUESTED:
                    mHandler.removeCallbacks(explicitClosingRunnable);
                    break;
                case OPENED:
                    mHandler.removeCallbacks(defaultClosingRunnable);
                    break;
                case CLOSED:
                case OPEN_FAILED:
                case OPEN_NOT_REQUESTED:
                    socketIsOpened = tryOpenServerSocket();
                    break;
            }

            if (!socketIsOpened) {
                serverSocketStatus = SocketsManager.ServerSocketStatus.OPEN_FAILED;
                logger.Error("Failed to open the socket server and return it");
                return null;
            }

            // Add back the default closing handler now
            mHandler.postDelayed(defaultClosingRunnable, DEFAULT_CLOSING_TIME_MILLS);
            serverSocketStatus = SocketsManager.ServerSocketStatus.OPENED;
            return mSocket;
        }

        @Nullable
        public Socket accept() throws IOException {
            ServerSocket socket = RequestSocketForUsage();
            if (socket != null) {
                return socket.accept();
            } else {
                return null;
            }
        }

        public SocketsManager.ServerSocketStatus getStatus() {
            return serverSocketStatus;
        }

        private boolean tryOpenServerSocket() {
            int attempt = 0;
            do {
                ++attempt;
                try {
                    this.mSocket = new ServerSocket(mPort);
                    break;
                } catch (Exception e) {
                    logger.Warn(e, "Failed to start ServerSocket on attempt: %s", Integer.toString(attempt));
                    synchronized (this) {
                        try {
                            wait(DEFAULT_RETRY_TIME_MILLS);
                        } catch (InterruptedException e1) {
                            logger.Error("Retry wait() interrupted");
                            e1.printStackTrace();
                        }
                    }
                }
            } while (attempt < 6);

            if (this.mSocket == null) {
                logger.Error("Failed to start ServerSocket");
                return false;
            } else {
                logger.Info("ServerSocket started");
                return true;
            }
        }
    }
}

----------------------------------------- LATER EDIT - ----------------------------------------

我总是在asyncTasks中触发getSocketAtPort()方法,这似乎是问题的一部分。

我现在在一个活动内部(在onCreate()内部)打开一个套接字(使用getSocketAtPort()),然后在asyncTasks中调用它。当我这样做时,所有处理程序都开始工作(包括asyncTask中请求的那些)。我的猜测是问题与线程有关。

0 个答案:

没有答案