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

com.path.android.jobqueue.nonPersistentQueue.MergedQueue Maven / Gradle / Ivy

Go to download

a Job Queue specifically written for Android to easily schedule jobs (tasks) that run in the background, improving UX and application stability.

There is a newer version: 1.1.2
Show newest version
package com.path.android.jobqueue.nonPersistentQueue;

import com.path.android.jobqueue.JobHolder;

import java.util.*;

/**
 * A queue implementation that utilize two queues depending on one or multiple properties of the {@link JobHolder}
 * While retrieving items, it uses a different comparison method to handle dynamic comparisons (e.g. time)
 * between two queues
 */
abstract public class MergedQueue implements JobSet {
    JobSet queue0;
    JobSet queue1;

    final Comparator comparator;
    final Comparator retrieveComparator;

    /**
     *
     * @param initialCapacity passed to {@link MergedQueue#createQueue(com.path.android.jobqueue.nonPersistentQueue.MergedQueue.SetId, int, java.util.Comparator)}
     * @param comparator passed to {@link MergedQueue#createQueue(com.path.android.jobqueue.nonPersistentQueue.MergedQueue.SetId, int, java.util.Comparator)}
     * @param retrieveComparator upon retrieval, if both queues return items, this comparator is used to decide which
     *                           one should be returned
     */
    public MergedQueue(int initialCapacity, Comparator comparator, Comparator retrieveComparator) {
        this.comparator = comparator;
        this.retrieveComparator = retrieveComparator;
        queue0 = createQueue(SetId.S0, initialCapacity, comparator);
        queue1 = createQueue(SetId.S1, initialCapacity, comparator);
    }

    /**
     * used to poll from one of the queues
     * @param queueId
     * @return
     */
    protected JobHolder pollFromQueue(SetId queueId, Collection excludeGroupIds) {
        if(queueId == SetId.S0) {
            return queue0.poll(excludeGroupIds);
        }
        return queue1.poll(excludeGroupIds);
    }

    /**
     * used to peek from one of the queues
     * @param queueId
     * @return
     */
    protected JobHolder peekFromQueue(SetId queueId, Collection excludeGroupIds) {
        if(queueId == SetId.S0) {
            return queue0.peek(excludeGroupIds);
        }
        return queue1.peek(excludeGroupIds);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean offer(JobHolder jobHolder) {
        SetId queueId = decideQueue(jobHolder);
        if(queueId == SetId.S0) {
            return queue0.offer(jobHolder);

        }
        return queue1.offer(jobHolder);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JobHolder poll(Collection excludeGroupIds) {
        JobHolder delayed = queue0.peek(excludeGroupIds);
        if(delayed == null) {
            return queue1.poll(excludeGroupIds);
        }
        //if queue for this job has changed, re-add it and try poll from scratch
        if(decideQueue(delayed) != SetId.S0) {
            //should be moved to the other queue
            queue0.remove(delayed);
            queue1.offer(delayed);
            return poll(excludeGroupIds);
        }
        JobHolder nonDelayed = queue1.peek(excludeGroupIds);
        if(nonDelayed == null) {
            queue0.remove(delayed);
            return delayed;
        }
        //if queue for this job has changed, re-add it and try poll from scratch
        if(decideQueue(nonDelayed) != SetId.S1) {
            queue0.offer(nonDelayed);
            queue1.remove(nonDelayed);
            return poll(excludeGroupIds);
        }
        //both are not null, need to compare and return the better
        int cmp = retrieveComparator.compare(delayed, nonDelayed);
        if(cmp == -1) {
            queue0.remove(delayed);
            return delayed;
        } else {
            queue1.remove(nonDelayed);
            return nonDelayed;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JobHolder peek(Collection excludeGroupIds) {
        JobHolder delayed = queue0.peek(excludeGroupIds);
        //if queue for this job has changed, re-add it and try peek from scratch
        if(delayed != null && decideQueue(delayed) != SetId.S0) {
            queue1.offer(delayed);
            queue0.remove(delayed);
            return peek(excludeGroupIds);
        }
        JobHolder nonDelayed = queue1.peek(excludeGroupIds);
        //if queue for this job has changed, re-add it and try peek from scratch
        if(nonDelayed != null && decideQueue(nonDelayed) != SetId.S1) {
            queue0.offer(nonDelayed);
            queue1.remove(nonDelayed);
            return peek(excludeGroupIds);
        }
        if(delayed == null) {
            return nonDelayed;
        }
        if(nonDelayed == null) {
            return delayed;
        }
        int cmp = retrieveComparator.compare(delayed, nonDelayed);
        if(cmp == -1) {
            return delayed;
        }
        return nonDelayed;
    }



    /**
     * {@inheritDoc}
     */
    @Override
    public void clear() {
        queue1.clear();
        queue0.clear();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean remove(JobHolder holder) {
        //we cannot check queue here, might be dynamic
        return queue1.remove(holder) || queue0.remove(holder);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int size() {
        return queue0.size() + queue1.size();
    }

    /**
     * decides which queue should the job holder go
     * if first queue, should return 0
     * if second queue, should return 1
     * is only called when an item is inserted. methods like remove always call both queues.
     * @param jobHolder
     * @return
     */
    abstract protected SetId decideQueue(JobHolder jobHolder);

    /**
     * called when we want to create the subsequent queues
     * @param initialCapacity
     * @param comparator
     * @return
     */
    abstract protected JobSet createQueue(SetId setId, int initialCapacity, Comparator comparator);

    public CountWithGroupIdsResult countReadyJobs(SetId setId, long now, Collection excludeGroups) {
        if(setId == SetId.S0) {
            return queue0.countReadyJobs(now, excludeGroups);
        } else {
            return queue1.countReadyJobs(now, excludeGroups);
        }
    }

    public CountWithGroupIdsResult countReadyJobs(SetId setId, Collection excludeGroups) {
        if(setId == SetId.S0) {
            return queue0.countReadyJobs(excludeGroups);
        } else {
            return queue1.countReadyJobs(excludeGroups);
        }
    }

    /**
     * simple enum to identify queues
     */
    protected static enum SetId {
        S0,
        S1
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy