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

com.landawn.abacus.android.util.Async Maven / Gradle / Ivy

There is a newer version: 1.10.1
Show newest version
/*
 * Copyright (c) 2015, Haiyang Li.
 *
 * 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.
 */

package com.landawn.abacus.android.util;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.landawn.abacus.util.MoreExecutors;
import com.landawn.abacus.util.Retry;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.Predicate;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;

// TODO: Auto-generated Javadoc
/**
 *
 * @author Haiyang Li
 * @since 0.8
 */
public class Async {

    static final ScheduledExecutorService SCHEDULED_EXECUTOR;
    static {
        final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(8);
        executor.setKeepAliveTime(180, TimeUnit.SECONDS);
        executor.allowCoreThreadTimeOut(true);
        executor.setRemoveOnCancelPolicy(true);
        SCHEDULED_EXECUTOR = MoreExecutors.getExitingScheduledExecutorService(executor);
    }

    static final _UIExecutor _UI_EXECUTOR = new _UIExecutor();

    public static final Executor SERIAL_EXECUTOR = AsyncTask.SERIAL_EXECUTOR;

    public static final Executor TP_EXECUTOR = AsyncTask.THREAD_POOL_EXECUTOR;

    public static final Executor UI_EXECUTOR = _UI_EXECUTOR;

    private Async() {
        // Singleton
    }

    /**
     * The action will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
     *
     * @param action
     * @return
     */
    static ContinuableFuture execute(final Throwables.Runnable action) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                action.run();
                return null;
            }
        }), SERIAL_EXECUTOR);
    }

    /**
     *
     * @param action
     * @param delayInMillis
     * @return
     */
    static ContinuableFuture execute(final Throwables.Runnable action, final long delayInMillis) {
        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return Async.execute(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delayInMillis, TimeUnit.MILLISECONDS);

        return new ContinuableFuture<>(wrap(scheduledFuture), null, SERIAL_EXECUTOR);
    }

    /**
     *
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes, final long retryIntervalInMillis,
            final Predicate retryCondition) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                Retry.of(retryTimes, retryIntervalInMillis, retryCondition).run(action);
                return null;
            }
        });
    }

    /**
     * The action will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
     *
     * @param 
     * @param action
     * @return
     */
    static  ContinuableFuture execute(final Callable action) {
        return execute(new FutureTask<>(action), SERIAL_EXECUTOR);
    }

    /**
     *
     * @param 
     * @param action
     * @param delayInMillis
     * @return
     */
    static  ContinuableFuture execute(final Callable action, final long delayInMillis) {
        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return Async.execute(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delayInMillis, TimeUnit.MILLISECONDS);

        return new ContinuableFuture<>(wrap(scheduledFuture), null, SERIAL_EXECUTOR);
    }

    /**
     *
     * @param 
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryIntervalInMillis,
            final BiPredicate retryCondition) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final Retry retry = Retry.of(retryTimes, retryIntervalInMillis, retryCondition);
                return retry.call(action);
            }
        });
    }

    /**
     * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
     *
     * @param action
     * @return
     */
    static ContinuableFuture executeWithThreadPool(final Throwables.Runnable action) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                action.run();
                return null;
            }
        }), TP_EXECUTOR);
    }

    /**
     * Execute with thread pool.
     *
     * @param action
     * @param delayInMillis
     * @return
     */
    static ContinuableFuture executeWithThreadPool(final Throwables.Runnable action, final long delayInMillis) {
        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return Async.executeWithThreadPool(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delayInMillis, TimeUnit.MILLISECONDS);

        return new ContinuableFuture<>(wrap(scheduledFuture), null, TP_EXECUTOR);
    }

    /**
     * Execute with thread pool.
     *
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static ContinuableFuture executeWithThreadPool(final Throwables.Runnable action, final int retryTimes,
            final long retryIntervalInMillis, final Predicate retryCondition) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                Retry.of(retryTimes, retryIntervalInMillis, retryCondition).run(action);
                return null;
            }
        });
    }

    /**
     * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
     *
     * @param 
     * @param action
     * @return
     */
    static  ContinuableFuture executeWithThreadPool(final Callable action) {
        return execute(new FutureTask<>(action), TP_EXECUTOR);
    }

    /**
     * Execute with thread pool.
     *
     * @param 
     * @param action
     * @param delayInMillis
     * @return
     */
    static  ContinuableFuture executeWithThreadPool(final Callable action, final long delayInMillis) {
        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return Async.executeWithThreadPool(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delayInMillis, TimeUnit.MILLISECONDS);

        return new ContinuableFuture<>(wrap(scheduledFuture), null, TP_EXECUTOR);
    }

    /**
     * Execute with thread pool.
     *
     * @param 
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static  ContinuableFuture executeWithThreadPool(final Callable action, final int retryTimes, final long retryIntervalInMillis,
            final BiPredicate retryCondition) {
        return executeWithThreadPool(new Callable() {
            @Override
            public R call() throws Exception {
                final Retry retry = Retry.of(retryTimes, retryIntervalInMillis, retryCondition);
                return retry.call(action);
            }
        });
    }

    /**
     * The action will be asynchronously executed in UI thread.
     *
     * @param action
     * @return
     */
    static ContinuableFuture executeOnUiThread(final Throwables.Runnable action) {
        return executeOnUiThread(action, 0);
    }

    /**
     * The action will be asynchronously executed in UI thread.
     *
     * @param action
     * @param delayInMillis
     * @return
     */
    static ContinuableFuture executeOnUiThread(final Throwables.Runnable action, final long delayInMillis) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                action.run();
                return null;
            }
        }), _UI_EXECUTOR, delayInMillis);
    }

    /**
     * Execute on ui thread.
     *
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static ContinuableFuture executeOnUiThread(final Throwables.Runnable action, final int retryTimes,
            final long retryIntervalInMillis, final Predicate retryCondition) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                Retry.of(retryTimes, retryIntervalInMillis, retryCondition).run(action);
                return null;
            }
        });
    }

    /**
     * The action will be asynchronously executed in UI thread.
     *
     * @param 
     * @param action
     * @return
     */
    static  ContinuableFuture executeOnUiThread(final Callable action) {
        return executeOnUiThread(action, 0);
    }

    /**
     * The action will be asynchronously executed in UI thread.
     *
     * @param 
     * @param action
     * @param delayInMillis
     * @return
     */
    static  ContinuableFuture executeOnUiThread(final Callable action, final long delayInMillis) {
        return execute(new FutureTask<>(action), _UI_EXECUTOR, delayInMillis);
    }

    /**
     * Execute on ui thread.
     *
     * @param 
     * @param action
     * @param retryTimes
     * @param retryIntervalInMillis the retry interval
     * @param retryCondition
     * @return
     */
    static  ContinuableFuture executeOnUiThread(final Callable action, final int retryTimes, final long retryIntervalInMillis,
            final BiPredicate retryCondition) {
        return executeOnUiThread(new Callable() {
            @Override
            public R call() throws Exception {
                final Retry retry = Retry.of(retryTimes, retryIntervalInMillis, retryCondition);
                return retry.call(action);
            }
        });
    }

    /**
     *
     * @param 
     * @param futureTask
     * @param executor
     * @return
     */
    private static  ContinuableFuture execute(final FutureTask futureTask, final Executor executor) {
        executor.execute(futureTask);

        return new ContinuableFuture<>(futureTask, null, executor);
    }

    /**
     *
     * @param 
     * @param futureTask
     * @param executor
     * @param delayInMillis
     * @return
     */
    private static  ContinuableFuture execute(final FutureTask futureTask, final _UIExecutor executor, final long delayInMillis) {
        executor.execute(futureTask, delayInMillis);

        return new ContinuableFuture<>(futureTask, null, executor);
    }

    /**
     *
     * @param 
     * @param scheduledFuture
     * @return
     */
    private static  Future wrap(final ScheduledFuture> scheduledFuture) {
        return new Future() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                if (scheduledFuture.cancel(mayInterruptIfRunning) && scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.cancel(mayInterruptIfRunning);
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public boolean isCancelled() {
                if (scheduledFuture.isCancelled() && scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.isCancelled();
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public boolean isDone() {
                if (scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.isDone();
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public R get() throws InterruptedException, ExecutionException {
                final ContinuableFuture resFuture = scheduledFuture.get();
                return resFuture == null ? null : resFuture.get();
            }

            @Override
            public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                final long beginTime = System.currentTimeMillis();

                final ContinuableFuture resFuture = scheduledFuture.get(timeout, unit);

                final long remainingTimeout = unit.toMillis(timeout) - (System.currentTimeMillis() - beginTime);

                return resFuture == null ? null : (remainingTimeout > 0 ? resFuture.get(remainingTimeout, TimeUnit.MILLISECONDS) : resFuture.get());
            }
        };
    }

    /**
     * The Class _UIExecutor.
     */
    static final class _UIExecutor implements Executor {

        /** The Constant HANDLER. */
        private static final Handler HANDLER = new Handler(Looper.getMainLooper());

        /**
         * Instantiates a new UI executor.
         */
        private _UIExecutor() {
            // Singleton.
        }

        /**
         *
         * @param command
         */
        @Override
        public void execute(Runnable command) {
            HANDLER.post(command);
        }

        /**
         *
         * @param command
         * @param delayInMillis
         */
        public void execute(Runnable command, final long delayInMillis) {
            if (delayInMillis > 0) {
                HANDLER.postDelayed(command, delayInMillis);
            } else {
                HANDLER.post(command);
            }
        }
    }

    /**
     * The Class SerialExecutor.
     */
    public static final class SerialExecutor {

        /**
         * Instantiates a new serial executor.
         */
        private SerialExecutor() {
            // singleton
        }

        /**
         * The action will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
         *
         * @param action
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action) {
            return Async.execute(action);
        }

        /**
         *
         * @param action
         * @param delayInMillis
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final long delayInMillis) {
            return Async.execute(action, delayInMillis);
        }

        /**
         *
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes,
                final long retryIntervalInMillis, final Predicate retryCondition) {
            return Async.execute(action, retryTimes, retryIntervalInMillis, retryCondition);

        }

        /**
         * The action will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
         *
         * @param 
         * @param action
         * @return
         */
        public static  ContinuableFuture execute(final Callable action) {
            return Async.execute(action);
        }

        /**
         *
         * @param 
         * @param action
         * @param delayInMillis
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final long delayInMillis) {
            return Async.execute(action, delayInMillis);
        }

        /**
         *
         * @param 
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryIntervalInMillis,
                final BiPredicate retryCondition) {
            return Async.execute(action, retryTimes, retryIntervalInMillis, retryCondition);
        }
    }

    /**
     * The Class TPExecutor.
     */
    public static final class TPExecutor {

        /**
         * Instantiates a new TP executor.
         */
        private TPExecutor() {
            // singleton
        }

        /**
         * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
         *
         * @param action
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action) {
            return Async.executeWithThreadPool(action);
        }

        /**
         *
         * @param action
         * @param delayInMillis
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final long delayInMillis) {
            return Async.executeWithThreadPool(action, delayInMillis);
        }

        /**
         *
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes,
                final long retryIntervalInMillis, final Predicate retryCondition) {
            return Async.executeWithThreadPool(action, retryTimes, retryIntervalInMillis, retryCondition);

        }

        /**
         * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
         *
         * @param 
         * @param action
         * @return
         */
        public static  ContinuableFuture execute(final Callable action) {
            return Async.executeWithThreadPool(action);
        }

        /**
         *
         * @param 
         * @param action
         * @param delayInMillis
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final long delayInMillis) {
            return Async.executeWithThreadPool(action, delayInMillis);
        }

        /**
         *
         * @param 
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryIntervalInMillis,
                final BiPredicate retryCondition) {
            return Async.executeWithThreadPool(action, retryTimes, retryIntervalInMillis, retryCondition);
        }
    }

    /**
     * The Class UIExecutor.
     */
    public static final class UIExecutor {

        /**
         * Instantiates a new UI executor.
         */
        private UIExecutor() {
            // singleton
        }

        /**
         * The action will be asynchronously executed in UI thread.
         *
         * @param action
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action) {
            return Async.executeOnUiThread(action);
        }

        /**
         * The action will be asynchronously executed in UI thread.
         *
         * @param action
         * @param delayInMillis unit is milliseconds
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final long delayInMillis) {
            return Async.executeOnUiThread(action, delayInMillis);
        }

        /**
         *
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes,
                final long retryIntervalInMillis, final Predicate retryCondition) {
            return Async.executeOnUiThread(action, retryTimes, retryIntervalInMillis, retryCondition);
        }

        /**
         * The action will be asynchronously executed in UI thread.
         *
         * @param 
         * @param action
         * @return
         */
        public static  ContinuableFuture execute(final Callable action) {
            return Async.executeOnUiThread(action);
        }

        /**
         * The action will be asynchronously executed in UI thread.
         *
         * @param 
         * @param action
         * @param delayInMillis
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final long delayInMillis) {
            return Async.executeOnUiThread(action, delayInMillis);
        }

        /**
         *
         * @param 
         * @param action
         * @param retryTimes
         * @param retryIntervalInMillisInMillis the retry interval
         * @param retryCondition
         * @return
         */
        public static  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryIntervalInMillisInMillis,
                final BiPredicate retryCondition) {
            return Async.executeOnUiThread(action, retryTimes, retryIntervalInMillisInMillis, retryCondition);
        }
    }

    //    /**
    //     * Short name for AsyncExecutor
    //     *
    //     * @deprecated replaced with SerialExecutor/TPExecutor/UIExecutor.
    //     */
    //    @Deprecated
    //    @Beta
    //    public static class Asyn extends AsyncExecutor {
    //        private Asyn() {
    //            // singleton
    //        }
    //    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy