Configuration.java
package com.birbit.android.jobqueue.config;
import android.content.Context;
import android.net.ConnectivityManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.DefaultQueueFactory;
import com.birbit.android.jobqueue.JobQueue;
import com.birbit.android.jobqueue.QueueFactory;
import com.birbit.android.jobqueue.di.DependencyInjector;
import com.birbit.android.jobqueue.log.CustomLogger;
import com.birbit.android.jobqueue.log.JqLog;
import com.birbit.android.jobqueue.network.NetworkUtil;
import com.birbit.android.jobqueue.network.NetworkUtilImpl;
import com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue;
import com.birbit.android.jobqueue.scheduling.Scheduler;
import com.birbit.android.jobqueue.timer.SystemTimer;
import com.birbit.android.jobqueue.timer.Timer;
import java.util.concurrent.ThreadFactory;
/**
* {@link com.birbit.android.jobqueue.JobManager} configuration object
*/
@SuppressWarnings("WeakerAccess")
public class Configuration {
/**
* The default id for a Job. If you have multiple JobManagers, you should set this value via
* {@link Builder#id(String)}
*/
public static final String DEFAULT_ID = "default_job_manager";
/**
* The default timeout for an idle thread before it is destroyed
*/
public static final int DEFAULT_THREAD_KEEP_ALIVE_SECONDS = 15;
/**
* The default number of jobs per thread before JobManager creates a new one
*/
public static final int DEFAULT_LOAD_FACTOR_PER_CONSUMER = 3;
/**
* The default max number of consumers that will be created by the JobManager
*/
public static final int MAX_CONSUMER_COUNT = 5;
/**
* The default min number of consumers that will be kept alive by the JobManager
*/
public static final int MIN_CONSUMER_COUNT = 0;
/**
* The default priority for new job consumers ({@code Thread.NORM_PRIORITY}).
*/
public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY;
String id = DEFAULT_ID;
int maxConsumerCount = MAX_CONSUMER_COUNT;
int minConsumerCount = MIN_CONSUMER_COUNT;
int consumerKeepAlive = DEFAULT_THREAD_KEEP_ALIVE_SECONDS;
int loadFactor = DEFAULT_LOAD_FACTOR_PER_CONSUMER;
Context appContext;
QueueFactory queueFactory;
DependencyInjector dependencyInjector;
NetworkUtil networkUtil;
CustomLogger customLogger = new JqLog.ErrorLogger();
Timer timer;
Scheduler scheduler;
boolean inTestMode = false;
boolean resetDelaysOnRestart = false;
int threadPriority = DEFAULT_THREAD_PRIORITY;
boolean batchSchedulerRequests = true;
ThreadFactory threadFactory = null;
private Configuration(){
//use builder instead
}
@NonNull
public Context getAppContext() {
return appContext;
}
@NonNull
public String getId() {
return id;
}
public boolean batchSchedulerRequests() {
return batchSchedulerRequests;
}
@NonNull
public QueueFactory getQueueFactory() {
return queueFactory;
}
@Nullable
public DependencyInjector getDependencyInjector() {
return dependencyInjector;
}
public int getConsumerKeepAlive() {
return consumerKeepAlive;
}
@NonNull
public NetworkUtil getNetworkUtil() {
return networkUtil;
}
public int getMaxConsumerCount() {
return maxConsumerCount;
}
public int getMinConsumerCount() {
return minConsumerCount;
}
@Nullable
public CustomLogger getCustomLogger() {
return customLogger;
}
public int getLoadFactor() {
return loadFactor;
}
public boolean isInTestMode() {
return inTestMode;
}
@NonNull
public Timer getTimer() {
return timer;
}
public boolean resetDelaysOnRestart() {
return resetDelaysOnRestart;
}
@Nullable
public Scheduler getScheduler() {
return scheduler;
}
public int getThreadPriority() {
return threadPriority;
}
@Nullable
public ThreadFactory getThreadFactory() {
return threadFactory;
}
@SuppressWarnings("unused")
public static final class Builder {
private Configuration configuration;
public Builder(@NonNull Context context) {
this.configuration = new Configuration();
this.configuration.appContext = context.getApplicationContext();
}
/**
* provide and ID for this job manager to be used while creating persistent queue. it is useful if you are going to
* create multiple instances of it.
* default id is {@link #DEFAULT_ID}
* @param id if you have multiple instances of job manager, you should provide an id to distinguish their persistent files.
* @return This Configuration for easy chaining
*/
@NonNull
public Builder id(@NonNull String id) {
configuration.id = id;
return this;
}
/**
* When JobManager runs out of `ready` jobs, it will keep consumers alive for this duration.
* It defaults to {@link #DEFAULT_THREAD_KEEP_ALIVE_SECONDS}
* @param keepAlive in seconds
* @return This Configuration for easy chaining
*/
@NonNull
public Builder consumerKeepAlive(int keepAlive) {
configuration.consumerKeepAlive = keepAlive;
return this;
}
/**
* JobManager 1.x versions used to clear delay for existing jobs when the application is
* restarted because there is no reliable way to measure time difference between device
* reboots (and from the app's perspective, device reboot is no different than app restart).
* <p>
* This may cause unexpected behaviors as delayed persistent jobs instantly become available
* when application restarts.
* <p>
* JobManager 2.x versions change this behavior and does not reset the delay of persistent
* jobs on restart. This may create a problem if jobs were added when the device's clock is
* set to some unreasonable time but for common cases, it is more desirable.
* <p>
* You can get the v1 behavior by calling this method. Note that it will also effect jobs
* which require network with a timeout. Their timeouts will be triggered on restart if you
* call this method.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder resetDelaysOnRestart() {
configuration.resetDelaysOnRestart = true;
return this;
}
/**
* JobManager needs one persistent and one non-persistent {@link JobQueue} to function.
* By default, it will use {@link SqliteJobQueue} and
* {@link com.birbit.android.jobqueue.inMemoryQueue.SimpleInMemoryPriorityQueue}
* You can provide your own implementation if they don't fit your needs. Make sure it passes all tests in
* {@code JobQueueTestBase} to ensure it will work fine.
* @param queueFactory your custom queue factory.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder queueFactory(@Nullable QueueFactory queueFactory) {
if(configuration.queueFactory != null && queueFactory != null) {
throw new RuntimeException("already set a queue factory. This might happen if"
+ "you've provided a custom job serializer");
}
configuration.queueFactory = queueFactory;
return this;
}
/**
* convenient configuration to replace job serializer while using {@link SqliteJobQueue}
* queue for persistence. By default, it uses a
* {@link com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue.JavaSerializer}
* which will use default Java serialization.
* @param jobSerializer The serializer to be used to persist jobs.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder jobSerializer(@NonNull SqliteJobQueue.JobSerializer jobSerializer) {
configuration.queueFactory = new DefaultQueueFactory(jobSerializer);
return this;
}
/**
* By default, Job Manager comes with a simple {@link NetworkUtilImpl} that queries {@link ConnectivityManager}
* to check if network connection exists. You can provide your own if you need a custom logic (e.g. check your
* server health etc).
*
* @param networkUtil The NetworkUtil to be used by the JobManager. If it is null, JobManager
* will use {@link NetworkUtilImpl}
* @return This Configuration for easy chaining
*/
@NonNull
public Builder networkUtil(@Nullable NetworkUtil networkUtil) {
configuration.networkUtil = networkUtil;
return this;
}
/**
* JobManager is suitable for DependencyInjection. Just provide your DependencyInjector and it will call it
* before {Job#onAdded} method is called.
* if job is persistent, it will also be called before run method.
*
* @param injector your dependency injector interface, if using one
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder injector(@Nullable DependencyInjector injector) {
configuration.dependencyInjector = injector;
return this;
}
/**
* # of max consumers to run concurrently. defaults to {@link #MAX_CONSUMER_COUNT}
* @param count The max number of threads that JobManager can create to run jobs
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder maxConsumerCount(int count) {
configuration.maxConsumerCount = count;
return this;
}
/**
* you can specify to keep minConsumers alive even if there are no ready jobs. defaults to
* {@link #MIN_CONSUMER_COUNT}
*
* @param count The min of of threads that JobManager will keep alive even if they are idle.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder minConsumerCount(int count) {
configuration.minConsumerCount = count;
return this;
}
/**
* You can specify a custom timer to control task execution. Useful for testing.
*
* @param timer The timer to use
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder timer(@Nullable Timer timer) {
configuration.timer = timer;
return this;
}
/**
* you can provide a custom logger to get logs from JobManager.
* by default, JobManager only logs error via Android's <code>Log.e</code>.
*
* @param logger The logger to be used by the JobManager.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder customLogger(@Nullable CustomLogger logger) {
configuration.customLogger = logger;
return this;
}
/**
* calculated by # of jobs (running+waiting) per thread
* for instance, at a given time, if you have two consumers and 10 jobs in waiting queue (or running right now), load is
* (10/2) =5
* defaults to {@link #DEFAULT_LOAD_FACTOR_PER_CONSUMER}
*
* @param loadFactor Number of available jobs per thread
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder loadFactor(int loadFactor) {
configuration.loadFactor = loadFactor;
return this;
}
/**
* Sets the JobManager in test mode. This information is passed to JobQueue's.
* If you are using default JobQueues, calling this method will cause {@link SqliteJobQueue}
* to use an in-memory database.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder inTestMode() {
configuration.inTestMode = true;
return this;
}
/**
* Assigns a scheduler that can be used to wake up the application when JobManager has jobs
* to execute. This is the integration point with the system
* {@link android.app.job.JobScheduler}.
* <p>
* <b>Batching</b>
* <p>
* By default, JobManager batches scheduling requests so that it will not call JobScheduler
* too many times. For instance, if a persistent job that requires network is added, when
* batching is enabled, JobManager creates the JobScheduler request with
* {@link com.birbit.android.jobqueue.BatchingScheduler#DEFAULT_BATCHING_PERIOD_IN_MS} delay.
* Any subsequent job request that has the same criteria will use the previous batching
* request. This way, JobManager can avoid making a JobScheduler request for every job.
* It will still execute the Job if it becomes available without waiting for the delay but
* if the application is killed, the JobScheduler will wait until the delay passes before
* waking up the application to consume the jobs.
*
* @param scheduler The scheduler to be used
* @param batch Defines whether the scheduling requests should be batched or not.
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder scheduler(@Nullable Scheduler scheduler, boolean batch) {
configuration.scheduler = scheduler;
configuration.batchSchedulerRequests = batch;
return this;
}
/**
* Sets the priority for the threads of this manager. By default it is
* {@link #DEFAULT_THREAD_PRIORITY}.
* <p>
* If a {@link ThreadFactory} is provided, this value is ignored.
*
* @param threadPriority The thread priority to be used for new jobs
*
* @return This Configuration for easy chaining
*/
@NonNull
public Builder consumerThreadPriority(int threadPriority) {
configuration.threadPriority = threadPriority;
return this;
}
/**
* Assigns a scheduler that can be used to wake up the application when JobManager has jobs
* to execute. This is the integration point with the system
* {@link android.app.job.JobScheduler}.
* <p>
* <b>Batching</b>
* <p>
* By default, JobManager batches scheduling requests so that it will not call JobScheduler
* too many times. For instance, if a persistent job that requires network is added, when
* batching is enabled, JobManager creates the JobScheduler request with
* {@link com.birbit.android.jobqueue.BatchingScheduler#DEFAULT_BATCHING_PERIOD_IN_MS} delay.
* Any subsequent job request that has the same criteria will use the previous batching
* request. This way, JobManager can avoid making a JobScheduler request for every job.
* It will still execute the Job if it becomes available without waiting for the delay but
* if the application is killed, the JobScheduler will wait until the delay passes before
* waking up the application to consume the jobs.
*
* @param scheduler The scheduler to be used
*
* @return This Configuration.Builder for easy chaining
*/
@NonNull
public Builder scheduler(@Nullable Scheduler scheduler) {
return scheduler(scheduler, true);
}
/**
* Provide a factory class to create new worker instances when JobManager needs them.
* <p>
* When a factory is installed, it becomes its responsibility to configure
* the {@link Thread} with proper group and priority. JobManager will use the {@link Thread}
* as is.
*
* @param threadFactory The factory to be used
*
* @return This Configuration.Builder for easy chaining
*/
@NonNull
public Builder threadFactory(@Nullable final ThreadFactory threadFactory) {
configuration.threadFactory = threadFactory;
return this;
}
@NonNull
public Configuration build() {
if(configuration.queueFactory == null) {
configuration.queueFactory = new DefaultQueueFactory();
}
if(configuration.networkUtil == null) {
configuration.networkUtil = new NetworkUtilImpl(configuration.appContext);
}
if (configuration.timer == null) {
configuration.timer = new SystemTimer();
}
return configuration;
}
}
}