All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zpf.tool.SingleGroupTask Maven / Gradle / Ivy

package com.zpf.tool;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Created by ZPF on 2021/2/18.
 */
public class SingleGroupTask {
    private long retryInterval = 3000;//失败重试间隔
    private long refreshInterval = 600000;//缓存刷新间隔
    private long cacheEffectiveTime = 0;//缓存有效时间
    private final long minIntervalTime = 200;//重调接口的最小时间间隔
    private long lastCacheTime = 0L;//上次缓存时间
    private long maxWaitTime = 630000L;//最大等待时间,避免忘记stop导致线程不释放
    private int maxRefreshCount = 1;//最大刷新次数:等于0--不刷新,小于0--无限刷新,大于0--有限次数刷新
    private int maxRetryCount = 1;//最大重试次数:等于0--不重试,小于0--无限重试,大于0--有限次数重试
    private int failCount = 0;//失败重试计数
    private int successCount = 0;//成功刷新计数
    private final Object lock = new Object();
    private R[] cacheArray;
    private ResultListener resultListener;
    private RequestExecutor requestExecutor;
    private int requestCount = 0;
    private volatile long nextRequestTime = 0L;
    private volatile boolean loading = false;
    private volatile Thread workThread = null;

    public void setRequestExecutor(RequestExecutor requestExecutor) {
        this.requestExecutor = requestExecutor;
    }

    public void setResultListener(ResultListener resultListener) {
        this.resultListener = resultListener;
    }

    public void setMaxRefreshCount(int maxRefreshCount) {
        this.maxRefreshCount = maxRefreshCount;
        successCount = 0;
    }

    public void setMaxRetryCount(int maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
        failCount = 0;
    }

    public void setCacheEffectiveTime(long cacheEffectiveTime) {
        this.cacheEffectiveTime = cacheEffectiveTime;
    }

    public void setRefreshInterval(long refreshInterval) {
        this.refreshInterval = Math.max(refreshInterval, minIntervalTime);
        maxWaitTime = Math.max(this.refreshInterval + 30000, maxWaitTime);
    }

    public void setRetryInterval(long retryInterval) {
        this.retryInterval = Math.max(retryInterval, minIntervalTime);
        maxWaitTime = Math.max(this.retryInterval + 30000, maxWaitTime);
    }

    public void reload(boolean onlyFail) {
        if (loading) {
            return;
        }
        if (!onlyFail) {
            cacheArray = null;
        }
        startLoad(requestCount);
    }

    public void stopLoad() {
        loading = false;
        if (workThread != null) {
            workThread.interrupt();
        }
        workThread = null;
    }

    public void startLoad() {
        startLoad(1);
    }

    public void startLoad(int size) {
        if (loading || requestExecutor == null || size <= 0) {
            return;
        }
        requestCount = size;
        if (workThread == null || workThread.isInterrupted()) {
            workThread = createThread();
            workThread.start();
        }
        successCount = 0;
        failCount = 0;
        nextRequestTime = 0;
        synchronized (lock) {
            lock.notify();
        }
    }

    public boolean isLiving() {
        return workThread != null && !workThread.isInterrupted();
    }

    public long getNextRequestTime() {
        return nextRequestTime;
    }

    public void clearCache() {
        if (loading) {
            return;
        }
        cacheArray = null;
    }

    private long calculateNextRequestTime(boolean success) {
        long nextRequestTime;
        if (success) {
            successCount++;
            if (successCount <= 0) {
                successCount = 1;
            }
            failCount = 0;
            if (maxRefreshCount < 0 || successCount <= maxRefreshCount) {
                nextRequestTime = System.currentTimeMillis() + refreshInterval + 20;
            } else {
                nextRequestTime = -1;
            }
        } else {
            failCount++;
            if (maxRetryCount < 0 || failCount <= maxRetryCount) {
                nextRequestTime = System.currentTimeMillis() + retryInterval;
            } else {
                nextRequestTime = -1;
            }
        }
        return nextRequestTime;
    }

    //发生异常导致回调时,返回size小于0
    private void callListener(final boolean success, final int size, @NonNull final List list) {
        if (resultListener != null) {
            resultListener.onResult(success, size, list);
        }
    }

    private Thread createThread() {
        return new Thread(new Runnable() {
            @Override
            public void run() {
                long startWaitTime = System.currentTimeMillis();
                long waitTimeout;
                final LinkedList requestIndexList = new LinkedList<>();
                try {
                    while (System.currentTimeMillis() - startWaitTime < maxWaitTime) {
                        synchronized (lock) {
                            if (nextRequestTime > 0) {
                                waitTimeout = nextRequestTime - System.currentTimeMillis();
                            } else if (nextRequestTime == 0) {
                                waitTimeout = 0;
                            } else {
                                waitTimeout = maxWaitTime;
                            }
                            final RequestExecutor executor = requestExecutor;
                            final int size = requestCount;
                            if (executor == null || size <= 0 || waitTimeout > 0) {
                                loading = false;
                                nextRequestTime = 0;
                                if (waitTimeout <= 0) {
                                    waitTimeout = maxWaitTime;
                                } else {
                                    waitTimeout = Math.max(waitTimeout, minIntervalTime);
                                }
                                //进入等待
                                startWaitTime = System.currentTimeMillis();
                                lock.wait(waitTimeout);
                                continue;
                            }
                            loading = true;
                            //检查缓存有效时间
                            if (cacheEffectiveTime <= 0 || System.currentTimeMillis() - lastCacheTime > cacheEffectiveTime) {
                                cacheArray = null;
                            }
                            if (cacheArray == null || cacheArray.length != size) {
                                cacheArray = (R[]) new Object[size];
                            }
                            final R[] resultCache = cacheArray;
                            requestIndexList.clear();
                            R cache;
                            for (int i = 0; i < size; i++) {
                                cache = resultCache[i];
                                if (cache == null) {
                                    requestIndexList.add(i);
                                }
                            }
                            final long delay;
                            if (requestIndexList.size() == 0) {
                                //全部读取缓存
                                nextRequestTime = SingleGroupTask.this.calculateNextRequestTime(true);
                                if (nextRequestTime < 0) {
                                    delay = maxWaitTime;
                                } else {
                                    delay = Math.max(nextRequestTime - System.currentTimeMillis(), minIntervalTime);
                                }
                                SingleGroupTask.this.callListener(true, size, Arrays.asList(resultCache));
                            } else {
                                final AtomicInteger count = new AtomicInteger(requestIndexList.size());
                                for (int index : requestIndexList) {
                                    final int n = index;
                                    executor.asyncRequest(index, new ResultCallback() {
                                        @Override
                                        public void callback(@Nullable R result) {
                                            resultCache[n] = result;
                                            if (count.decrementAndGet() == 0) {
                                                boolean success = true;
                                                for (R r : resultCache) {
                                                    if (r == null) {
                                                        success = false;
                                                        break;
                                                    }
                                                }
                                                lastCacheTime = System.currentTimeMillis();
                                                nextRequestTime = SingleGroupTask.this.calculateNextRequestTime(success);
                                                SingleGroupTask.this.callListener(success, size, Arrays.asList(resultCache));
                                                cacheArray = resultCache;
                                                if (nextRequestTime >= 0) {
                                                    synchronized (lock) {
                                                        lock.notify();
                                                    }
                                                }
                                            }
                                        }
                                    });
                                }
                                delay = maxWaitTime;
                            }
                            loading = false;
                            if (delay > 0) {
                                //进入等待
                                startWaitTime = System.currentTimeMillis();
                                lock.wait(delay);
                            }
                        }
                    }
                } catch (Exception e) {
                    if (loading) {
                        e.printStackTrace();
                        //发生异常,触发回调
                        SingleGroupTask.this.callListener(false, -1, (List) Collections.emptyList());
                    }
                } finally {
                    loading = false;
                    workThread = null;
                }
            }
        });
    }

    public interface ResultCallback {
        void callback(@Nullable T result);
    }

    public interface ResultListener {
        void onResult(boolean success, int requestSize, @NonNull List resultList);
    }

    public interface RequestExecutor {
        void asyncRequest(int index, ResultCallback callback);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy