├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── build.gradle ├── examples └── twitter │ ├── README.md │ └── TwitterClient │ ├── build.gradle │ └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── birbit │ │ └── android │ │ └── jobqueue │ │ └── examples │ │ └── twitter │ │ ├── Config.java │ │ ├── SampleTwitterClient.java │ │ ├── Test.java │ │ ├── TwitterApplication.java │ │ ├── activities │ │ └── BaseActivity.java │ │ ├── adapters │ │ └── LazyListAdapter.java │ │ ├── controllers │ │ └── TwitterController.java │ │ ├── dao │ │ ├── DaoMaster.java │ │ ├── DaoSession.java │ │ └── TweetDao.java │ │ ├── entities │ │ ├── Tweet.java │ │ └── TweetBase.java │ │ ├── events │ │ ├── DeletedTweetEvent.java │ │ ├── FetchedNewTweetsEvent.java │ │ ├── PostedTweetEvent.java │ │ └── PostingTweetEvent.java │ │ ├── jobs │ │ ├── FetchTweetsJob.java │ │ ├── PostTweetJob.java │ │ └── Priority.java │ │ ├── models │ │ ├── DbHelper.java │ │ └── TweetModel.java │ │ ├── services │ │ ├── MyGcmJobService.java │ │ └── MyJobService.java │ │ └── tasks │ │ └── SimpleBackgroundTask.java │ └── res │ ├── layout │ ├── list_tweet.xml │ └── main.xml │ └── values │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jobqueue ├── LICENSE.txt ├── build.gradle ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── birbit │ │ └── android │ │ └── jobqueue │ │ ├── AsyncAddCallback.java │ │ ├── BatchingScheduler.java │ │ ├── CallbackManager.java │ │ ├── CancelHandler.java │ │ ├── CancelReason.java │ │ ├── CancelResult.java │ │ ├── Constraint.java │ │ ├── ConsumerManager.java │ │ ├── DefaultQueueFactory.java │ │ ├── IntCallback.java │ │ ├── Job.java │ │ ├── JobHolder.java │ │ ├── JobManager.java │ │ ├── JobManagerThread.java │ │ ├── JobQueue.java │ │ ├── JobStatus.java │ │ ├── Params.java │ │ ├── QueueFactory.java │ │ ├── RetryConstraint.java │ │ ├── RunningJobSet.java │ │ ├── TagConstraint.java │ │ ├── WrongThreadException.java │ │ ├── cachedQueue │ │ └── CachedJobQueue.java │ │ ├── callback │ │ ├── JobManagerCallback.java │ │ └── JobManagerCallbackAdapter.java │ │ ├── config │ │ └── Configuration.java │ │ ├── di │ │ └── DependencyInjector.java │ │ ├── inMemoryQueue │ │ └── SimpleInMemoryPriorityQueue.java │ │ ├── log │ │ ├── CustomLogger.java │ │ └── JqLog.java │ │ ├── messaging │ │ ├── DelayedMessageBag.java │ │ ├── Message.java │ │ ├── MessageFactory.java │ │ ├── MessagePredicate.java │ │ ├── MessageQueue.java │ │ ├── MessageQueueConsumer.java │ │ ├── PriorityMessageQueue.java │ │ ├── SafeMessageQueue.java │ │ ├── Type.java │ │ ├── UnsafeMessageQueue.java │ │ └── message │ │ │ ├── AddJobMessage.java │ │ │ ├── CallbackMessage.java │ │ │ ├── CancelMessage.java │ │ │ ├── CancelResultMessage.java │ │ │ ├── CommandMessage.java │ │ │ ├── ConstraintChangeMessage.java │ │ │ ├── JobConsumerIdleMessage.java │ │ │ ├── PublicQueryMessage.java │ │ │ ├── RunJobMessage.java │ │ │ ├── RunJobResultMessage.java │ │ │ └── SchedulerMessage.java │ │ ├── network │ │ ├── NetworkEventProvider.java │ │ ├── NetworkUtil.java │ │ └── NetworkUtilImpl.java │ │ ├── persistentQueue │ │ └── sqlite │ │ │ ├── DbOpenHelper.java │ │ │ ├── FileStorage.java │ │ │ ├── SqlHelper.java │ │ │ ├── SqliteJobQueue.java │ │ │ ├── Where.java │ │ │ └── WhereQueryCache.java │ │ ├── scheduling │ │ ├── FrameworkJobSchedulerService.java │ │ ├── FrameworkScheduler.java │ │ ├── GcmJobSchedulerService.java │ │ ├── GcmScheduler.java │ │ ├── Scheduler.java │ │ └── SchedulerConstraint.java │ │ └── timer │ │ ├── SystemTimer.java │ │ └── Timer.java │ └── test │ ├── java │ └── com │ │ └── birbit │ │ └── android │ │ └── jobqueue │ │ ├── BatchingSchedulerTest.java │ │ ├── ConsumerControllerTest.java │ │ ├── ConsumerTest.java │ │ ├── JobManagerThreadRunnable.java │ │ ├── JobManagerTrojan.java │ │ ├── SystemTimerTest.java │ │ ├── TestConstraint.java │ │ ├── config │ │ └── ConfigurationBuilderTest.java │ │ ├── messaging │ │ ├── DelayedMessageBagAddTest.java │ │ ├── DelayedMessageBagRecycleTest.java │ │ ├── DelayedMessageBagRemoveTest.java │ │ ├── MessageFactoryTest.java │ │ ├── MessageQueueTestBase.java │ │ ├── PriorityMessageQueueTest.java │ │ ├── SafeMessageQueueTest.java │ │ └── UnsafeMessageQueueTest.java │ │ ├── scheduling │ │ ├── FrameworkJobSchedulerServiceTest.java │ │ ├── FrameworkSchedulerTest.java │ │ ├── GcmJobSchedulerServiceTest.java │ │ ├── GcmSchedulerTest.java │ │ ├── MockFwService.java │ │ └── MockGcmService.java │ │ ├── test │ │ ├── TestBase.java │ │ ├── jobmanager │ │ │ ├── AddInBackgroundTest.java │ │ │ ├── AddedCountTest.java │ │ │ ├── ApplicationContextTests.java │ │ │ ├── AssertThreadsTest.java │ │ │ ├── CallbackTest.java │ │ │ ├── CancelBeforeRunningTest.java │ │ │ ├── CancelFailingJobsTest.java │ │ │ ├── CancelWhileRunningTest.java │ │ │ ├── CancelWhileRunningWithGroupsTest.java │ │ │ ├── CancelWithNetworkToggleTest.java │ │ │ ├── ClearTest.java │ │ │ ├── ConsumerCountTest.java │ │ │ ├── CountTest.java │ │ │ ├── DeadlineTest.java │ │ │ ├── DelayTest.java │ │ │ ├── DelayedRunTest.java │ │ │ ├── GroupingTest.java │ │ │ ├── HitDeadlineAfterException.java │ │ │ ├── InjectorTest.java │ │ │ ├── JobManagerTestBase.java │ │ │ ├── JobStatusTest.java │ │ │ ├── KeepAliveTest.java │ │ │ ├── LoadFactorTest.java │ │ │ ├── MultiThreadTest.java │ │ │ ├── NetworkJobTest.java │ │ │ ├── NetworkJobWithConnectivityListenerTest.java │ │ │ ├── NetworkNextJobTest.java │ │ │ ├── NonSerializableJobTest.java │ │ │ ├── PersistentJobTest.java │ │ │ ├── PriorityTest.java │ │ │ ├── ReRunWithLimitTest.java │ │ │ ├── RetryLogicTest.java │ │ │ ├── RunFailingJobTest.java │ │ │ ├── RunManyNonPersistentTest.java │ │ │ ├── SchedulerSimpleTestCase.java │ │ │ ├── SessionIdTest.java │ │ │ ├── SingleIdTest.java │ │ │ ├── SlowOnAddedTest.java │ │ │ └── ThreadFactoryTest.java │ │ ├── jobqueue │ │ │ ├── CachedPersistentJobQueueTest.java │ │ │ ├── JobParamsTest.java │ │ │ ├── JobQueueTestBase.java │ │ │ ├── SimpleInMemoryJobQueueTest.java │ │ │ └── SqliteJobQueueTest.java │ │ ├── jobs │ │ │ └── DummyJob.java │ │ ├── timer │ │ │ └── MockTimer.java │ │ └── util │ │ │ ├── JobQueueFactory.java │ │ │ └── RunningJobSetTest.java │ │ └── testing │ │ ├── CleanupRule.java │ │ ├── CollectLogsRule.java │ │ ├── StackTraceRule.java │ │ └── ThreadDumpRule.java │ └── resources │ └── robolectric.properties ├── lint ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── java │ └── com │ └── birbit │ └── android │ └── jobqueue │ └── lint │ ├── JobQueueDevelopmentLintRegistery.java │ ├── NotifyOnObjectDetector.java │ ├── SleepDetector.java │ ├── SystemTimeDetector.java │ └── WaitOnObjectWithTimeDetector.java └── settings.gradle /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: JDK ${{ matrix.java_version }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | java_version: [1.8] 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v1 15 | - name: Gradle Wrapper Validation 16 | uses: gradle/wrapper-validation-action@v1 17 | - name: Install JDK ${{ matrix.java_version }} 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: ${{ matrix.java_version }} 21 | - name: Build with Gradle 22 | run: ./gradlew check :jobqueue:createDebugCoverageReport --stacktrace -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # release configuration 19 | releaseConfig.properties 20 | 21 | # Eclipse project files 22 | .classpath 23 | .project 24 | .idea 25 | .css 26 | *.html 27 | .img 28 | .DS_Store 29 | jobqueue/out 30 | coverage-report 31 | junitvmwatcher*.properties 32 | jobqueue/cobertura.ser 33 | jobqueue/javadoc 34 | out 35 | *.iml 36 | pages 37 | .gradle 38 | build 39 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.3' 10 | classpath 'com.vanniktech:gradle-maven-publish-plugin:0.8.0' 11 | classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | jcenter() 20 | } 21 | } -------------------------------------------------------------------------------- /examples/twitter/README.md: -------------------------------------------------------------------------------- 1 | **build and run** 2 | gradle installDebug runTwitter -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | class RunApk extends DefaultTask { 4 | @TaskAction 5 | def runApp() { 6 | def adbExec = "${project.android.getSdkDirectory().getAbsolutePath()}/platform-tools/adb" 7 | println "running path on device or emulator" 8 | println "adb:" + adbExec 9 | def cmd = adbExec + " shell am start -a android.intent.action.MAIN -n com.birbit.android.jobqueue.examples.twitter/com.birbit.android.jobqueue.examples.twitter.SampleTwitterClient" 10 | println cmd 11 | def proc = cmd.execute() 12 | proc.in.eachLine {line -> println line} 13 | proc.err.eachLine {line -> println 'ERROR: ' + line} 14 | proc.waitFor() 15 | } 16 | } 17 | 18 | tasks.create(name: "runTwitter", type: RunApk) 19 | 20 | android { 21 | compileSdkVersion 29 22 | defaultConfig { 23 | applicationId "com.birbit.android.jobqueue.examples.twitter" 24 | minSdkVersion 15 25 | targetSdkVersion 29 26 | } 27 | 28 | dependencies { 29 | implementation 'org.greenrobot:greendao:3.2.2' 30 | implementation 'org.greenrobot:eventbus:3.1.1' 31 | implementation 'androidx.annotation:annotation:1.1.0' 32 | implementation 'org.twitter4j:twitter4j-core:3.0.5' 33 | implementation project(":jobqueue") 34 | implementation 'com.google.android.gms:play-services-gcm:17.0.0' 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/Config.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter; 2 | 3 | public class Config { 4 | public static final String CONSUMER_KEY = "GfonALJ3wScsJfPsjLpl5g"; 5 | public static final String CONSUMER_SECRET = "7EYvqptQeBQ9FFcbaPHv0WVe9rRbDi8dmX9DffIMIE"; 6 | 7 | public static final String ACCESS_TOKEN = "1443060589-h6JU83NsHMYx5M47Is2RzlVZmvHPbxQND9xT6KQ"; 8 | public static final String ACCESS_TOKEN_SECRET = "QLut9Mgwge5WptlVnCz9wxmbJrqBFNazkEYrGDZKYE"; 9 | 10 | public static final String REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token"; 11 | public static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize"; 12 | public static final String ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token"; 13 | } 14 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/Test.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter; 2 | 3 | /** 4 | * Created by yboyar on 3/20/16. 5 | */ 6 | public class Test { 7 | } 8 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/TwitterApplication.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter; 2 | 3 | import android.app.Application; 4 | import android.os.Build; 5 | import android.util.Log; 6 | 7 | import com.birbit.android.jobqueue.examples.twitter.services.MyGcmJobService; 8 | import com.birbit.android.jobqueue.scheduling.FrameworkJobSchedulerService; 9 | import com.birbit.android.jobqueue.JobManager; 10 | import com.birbit.android.jobqueue.config.Configuration; 11 | import com.birbit.android.jobqueue.examples.twitter.services.MyJobService; 12 | import com.birbit.android.jobqueue.log.CustomLogger; 13 | import com.birbit.android.jobqueue.scheduling.GcmJobSchedulerService; 14 | import com.google.android.gms.common.ConnectionResult; 15 | import com.google.android.gms.common.GoogleApiAvailability; 16 | 17 | 18 | public class TwitterApplication extends Application { 19 | private static TwitterApplication instance; 20 | private JobManager jobManager; 21 | 22 | public TwitterApplication() { 23 | instance = this; 24 | } 25 | 26 | @Override 27 | public void onCreate() { 28 | super.onCreate(); 29 | getJobManager();// ensure it is created 30 | } 31 | 32 | private void configureJobManager() { 33 | Configuration.Builder builder = new Configuration.Builder(this) 34 | .customLogger(new CustomLogger() { 35 | private static final String TAG = "JOBS"; 36 | @Override 37 | public boolean isDebugEnabled() { 38 | return true; 39 | } 40 | 41 | @Override 42 | public void d(String text, Object... args) { 43 | Log.d(TAG, String.format(text, args)); 44 | } 45 | 46 | @Override 47 | public void e(Throwable t, String text, Object... args) { 48 | Log.e(TAG, String.format(text, args), t); 49 | } 50 | 51 | @Override 52 | public void e(String text, Object... args) { 53 | Log.e(TAG, String.format(text, args)); 54 | } 55 | 56 | @Override 57 | public void v(String text, Object... args) { 58 | 59 | } 60 | }) 61 | .minConsumerCount(1)//always keep at least one consumer alive 62 | .maxConsumerCount(3)//up to 3 consumers at a time 63 | .loadFactor(3)//3 jobs per consumer 64 | .consumerKeepAlive(120);//wait 2 minute 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 66 | builder.scheduler(FrameworkJobSchedulerService.createSchedulerFor(this, 67 | MyJobService.class), true); 68 | } else { 69 | int enableGcm = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this); 70 | if (enableGcm == ConnectionResult.SUCCESS) { 71 | builder.scheduler(GcmJobSchedulerService.createSchedulerFor(this, 72 | MyGcmJobService.class), true); 73 | } 74 | } 75 | jobManager = new JobManager(builder.build()); 76 | } 77 | 78 | public synchronized JobManager getJobManager() { 79 | if (jobManager == null) { 80 | configureJobManager(); 81 | } 82 | return jobManager; 83 | } 84 | 85 | public static TwitterApplication getInstance() { 86 | return instance; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/activities/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.activities; 2 | 3 | import android.app.Activity; 4 | 5 | public class BaseActivity extends Activity { 6 | private boolean visible = false; 7 | 8 | @Override 9 | protected void onResume() { 10 | super.onResume(); 11 | visible = true; 12 | } 13 | 14 | @Override 15 | protected void onPause() { 16 | super.onPause(); 17 | visible = false; 18 | } 19 | 20 | public boolean isVisible() { 21 | return visible; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/adapters/LazyListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.adapters; 2 | 3 | import android.widget.BaseAdapter; 4 | import org.greenrobot.greendao.query.LazyList; 5 | 6 | abstract public class LazyListAdapter extends BaseAdapter { 7 | LazyList lazyList = null; 8 | public LazyListAdapter() { 9 | 10 | } 11 | 12 | public LazyListAdapter(LazyList initialList) { 13 | lazyList = initialList; 14 | } 15 | 16 | public void replaceLazyList(LazyList newList) { 17 | if(lazyList != null) { 18 | lazyList.close(); 19 | } 20 | lazyList = newList; 21 | notifyDataSetChanged(); 22 | } 23 | 24 | @Override 25 | public int getCount() { 26 | return lazyList == null ? 0 : lazyList.size(); 27 | } 28 | 29 | @Override 30 | public T getItem(int i) { 31 | return lazyList == null ? null : lazyList.get(i); 32 | } 33 | 34 | public void close() { 35 | if(lazyList != null) { 36 | lazyList.close(); 37 | lazyList = null; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/controllers/TwitterController.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.controllers; 2 | 3 | import com.birbit.android.jobqueue.examples.twitter.Config; 4 | import twitter4j.*; 5 | import twitter4j.auth.AccessToken; 6 | import twitter4j.conf.ConfigurationBuilder; 7 | 8 | import java.util.List; 9 | 10 | public class TwitterController { 11 | private static TwitterController instance; 12 | private Twitter twitter; 13 | // in a real app, this would be saved on login and come from shared preferences on startup 14 | private final long userId = 1443060589; 15 | public static final int PAGE_LENGTH = 20; 16 | 17 | 18 | public synchronized static TwitterController getInstance() { 19 | if(instance == null) { 20 | instance = new TwitterController(); 21 | } 22 | return instance; 23 | } 24 | 25 | public TwitterController() { 26 | twitter = new TwitterFactory(new ConfigurationBuilder() 27 | .setOAuthAccessToken(Config.ACCESS_TOKEN) 28 | .setOAuthAccessTokenSecret(Config.ACCESS_TOKEN_SECRET) 29 | .setDebugEnabled(true) 30 | .setOAuthConsumerKey(Config.CONSUMER_KEY) 31 | .setOAuthConsumerKey(Config.CONSUMER_SECRET) 32 | .build()).getSingleton(); 33 | AccessToken accessToken = new AccessToken(Config.ACCESS_TOKEN, Config.ACCESS_TOKEN_SECRET); 34 | twitter.setOAuthConsumer(Config.CONSUMER_KEY, Config.CONSUMER_SECRET); 35 | twitter.setOAuthAccessToken(accessToken); 36 | } 37 | 38 | public List loadTweets(Long sinceId) throws TwitterException { 39 | Paging paging = new Paging(); 40 | paging.setCount(PAGE_LENGTH); 41 | if(sinceId != null) { 42 | paging.setSinceId(sinceId); 43 | } 44 | return twitter.getHomeTimeline(paging); 45 | } 46 | 47 | public Status postTweet(String status) throws TwitterException { 48 | return twitter.updateStatus(status); 49 | } 50 | 51 | public long getUserId() throws TwitterException { 52 | return userId; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/dao/DaoMaster.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.dao; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteDatabase.CursorFactory; 6 | import android.database.sqlite.SQLiteOpenHelper; 7 | import android.util.Log; 8 | import org.greenrobot.greendao.AbstractDaoMaster; 9 | import org.greenrobot.greendao.AbstractDaoSession; 10 | import org.greenrobot.greendao.database.Database; 11 | import org.greenrobot.greendao.identityscope.IdentityScopeType; 12 | 13 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 14 | /** 15 | * Master of DAO (schema version 3): knows all DAOs. 16 | */ 17 | public class DaoMaster extends AbstractDaoMaster { 18 | public static final int SCHEMA_VERSION = 3; 19 | 20 | /** Creates underlying database table using DAOs. */ 21 | public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) { 22 | TweetDao.createTable(db, ifNotExists); 23 | } 24 | 25 | /** Drops underlying database table using DAOs. */ 26 | public static void dropAllTables(SQLiteDatabase db, boolean ifExists) { 27 | TweetDao.dropTable(db, ifExists); 28 | } 29 | 30 | public static abstract class OpenHelper extends SQLiteOpenHelper { 31 | 32 | public OpenHelper(Context context, String name, CursorFactory factory) { 33 | super(context, name, factory, SCHEMA_VERSION); 34 | } 35 | 36 | @Override 37 | public void onCreate(SQLiteDatabase db) { 38 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); 39 | createAllTables(db, false); 40 | } 41 | } 42 | 43 | /** WARNING: Drops all table on Upgrade! Use only during development. */ 44 | public static class DevOpenHelper extends OpenHelper { 45 | public DevOpenHelper(Context context, String name, CursorFactory factory) { 46 | super(context, name, factory); 47 | } 48 | 49 | @Override 50 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 51 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); 52 | dropAllTables(db, true); 53 | onCreate(db); 54 | } 55 | } 56 | 57 | public DaoMaster(Database db, int schemaVersion) { 58 | super(db, schemaVersion); 59 | registerDaoClass(TweetDao.class); 60 | } 61 | 62 | @Override public AbstractDaoSession newSession(IdentityScopeType type) { 63 | return new DaoSession(db, type, daoConfigMap); 64 | } 65 | 66 | public DaoSession newSession() { 67 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/dao/DaoSession.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.dao; 2 | 3 | import java.util.Map; 4 | 5 | import com.birbit.android.jobqueue.examples.twitter.entities.Tweet; 6 | import org.greenrobot.greendao.AbstractDao; 7 | import org.greenrobot.greendao.AbstractDaoSession; 8 | import org.greenrobot.greendao.database.Database; 9 | import org.greenrobot.greendao.identityscope.IdentityScopeType; 10 | import org.greenrobot.greendao.internal.DaoConfig; 11 | 12 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 13 | 14 | /** 15 | * {@inheritDoc} 16 | * 17 | * @see de.greenrobot.dao.AbstractDaoSession 18 | */ 19 | public class DaoSession extends AbstractDaoSession { 20 | 21 | private final DaoConfig tweetDaoConfig; 22 | 23 | private final TweetDao tweetDao; 24 | 25 | public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> 26 | daoConfigMap) { 27 | super(db); 28 | 29 | tweetDaoConfig = daoConfigMap.get(TweetDao.class).clone(); 30 | tweetDaoConfig.initIdentityScope(type); 31 | 32 | tweetDao = new TweetDao(tweetDaoConfig, this); 33 | 34 | registerDao(Tweet.class, tweetDao); 35 | } 36 | 37 | public void clear() { 38 | tweetDaoConfig.getIdentityScope().clear(); 39 | } 40 | 41 | public void deleteAllData() { 42 | tweetDao.deleteAll(); 43 | } 44 | 45 | 46 | public TweetDao getTweetDao() { 47 | return tweetDao; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/entities/Tweet.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.entities; 2 | 3 | 4 | 5 | // THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS 6 | 7 | // KEEP INCLUDES - put your custom includes here 8 | import twitter4j.Status; 9 | // KEEP INCLUDES END 10 | /** 11 | * Entity mapped to table TWEET. 12 | */ 13 | public class Tweet extends TweetBase { 14 | // KEEP FIELDS - put your custom fields here 15 | // KEEP FIELDS END 16 | public Tweet() { 17 | } 18 | 19 | public Tweet(Long localId) { 20 | super(localId); 21 | } 22 | 23 | public Tweet(Long localId, Long serverId, String text, Long userId, Boolean isLocal, java.util.Date createdAt) { 24 | super(localId, serverId, text, userId, isLocal, createdAt); 25 | } 26 | 27 | // KEEP METHODS - put your custom methods here 28 | public Tweet(Status status) { 29 | super(null, status.getId(), status.getText(), status.getUser().getId(), false, status.getCreatedAt()); 30 | } 31 | 32 | @Override 33 | public void onBeforeSave() { 34 | isLocal = serverId == null; 35 | super.onBeforeSave(); 36 | } 37 | // KEEP METHODS END 38 | 39 | } 40 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/entities/TweetBase.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.entities; 2 | 3 | 4 | 5 | 6 | 7 | 8 | // THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS 9 | 10 | // KEEP INCLUDES - put your custom includes here 11 | // KEEP INCLUDES END 12 | /** 13 | * Entity mapped to table TWEET. 14 | */ 15 | abstract public class TweetBase { 16 | 17 | protected Long localId; 18 | protected Long serverId; 19 | protected String text; 20 | protected Long userId; 21 | protected Boolean isLocal; 22 | protected java.util.Date createdAt; 23 | 24 | 25 | 26 | 27 | // KEEP FIELDS - put your custom fields here 28 | // KEEP FIELDS END 29 | 30 | public TweetBase() { 31 | } 32 | 33 | public TweetBase(Long localId) { 34 | this.localId = localId; 35 | } 36 | 37 | public TweetBase(Long localId, Long serverId, String text, Long userId, Boolean isLocal, java.util.Date createdAt) { 38 | this.localId = localId; 39 | this.serverId = serverId; 40 | this.text = text; 41 | this.userId = userId; 42 | this.isLocal = isLocal; 43 | this.createdAt = createdAt; 44 | } 45 | 46 | public Long getLocalId() { 47 | return localId; 48 | } 49 | 50 | public void setLocalId(Long localId) { 51 | this.localId = localId; 52 | } 53 | 54 | public Long getServerId() { 55 | return serverId; 56 | } 57 | 58 | public void setServerId(Long serverId) { 59 | this.serverId = serverId; 60 | } 61 | 62 | public String getText() { 63 | return text; 64 | } 65 | 66 | public void setText(String text) { 67 | this.text = text; 68 | } 69 | 70 | public Long getUserId() { 71 | return userId; 72 | } 73 | 74 | public void setUserId(Long userId) { 75 | this.userId = userId; 76 | } 77 | 78 | public Boolean getIsLocal() { 79 | return isLocal; 80 | } 81 | 82 | public void setIsLocal(Boolean isLocal) { 83 | this.isLocal = isLocal; 84 | } 85 | 86 | public java.util.Date getCreatedAt() { 87 | return createdAt; 88 | } 89 | 90 | public void setCreatedAt(java.util.Date createdAt) { 91 | this.createdAt = createdAt; 92 | } 93 | 94 | public void updateNotNull(Tweet other) { 95 | if(this == other) { 96 | return;//both came from db, no need to run this. 97 | } 98 | 99 | if(other.localId != null) { 100 | this.localId = other.localId; 101 | } 102 | 103 | 104 | if(other.serverId != null) { 105 | this.serverId = other.serverId; 106 | } 107 | 108 | 109 | if(other.text != null) { 110 | this.text = other.text; 111 | } 112 | 113 | 114 | if(other.userId != null) { 115 | this.userId = other.userId; 116 | } 117 | 118 | 119 | if(other.isLocal != null) { 120 | this.isLocal = other.isLocal; 121 | } 122 | 123 | 124 | if(other.createdAt != null) { 125 | this.createdAt = other.createdAt; 126 | } 127 | 128 | // relationships 129 | } 130 | 131 | 132 | // KEEP METHODS - put your custom methods here 133 | // KEEP METHODS END 134 | 135 | public void onBeforeSave() { 136 | //you can override this method and do some stuff if you want to :) 137 | 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/events/DeletedTweetEvent.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.events; 2 | 3 | public class DeletedTweetEvent { 4 | private long id; 5 | public DeletedTweetEvent(long id) { 6 | this.id = id; 7 | } 8 | 9 | public long getId() { 10 | return id; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/events/FetchedNewTweetsEvent.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.events; 2 | 3 | public class FetchedNewTweetsEvent { 4 | } 5 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/events/PostedTweetEvent.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.events; 2 | 3 | import com.birbit.android.jobqueue.examples.twitter.entities.Tweet; 4 | 5 | public class PostedTweetEvent { 6 | private Tweet tweet; 7 | private long localId; 8 | 9 | public PostedTweetEvent(Tweet tweet, long localId) { 10 | this.tweet = tweet; 11 | this.localId = localId; 12 | } 13 | 14 | public Tweet getTweet() { 15 | return tweet; 16 | } 17 | 18 | public long getLocalId() { 19 | return localId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/events/PostingTweetEvent.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.events; 2 | 3 | import com.birbit.android.jobqueue.examples.twitter.entities.Tweet; 4 | 5 | public class PostingTweetEvent { 6 | private Tweet tweeet; 7 | 8 | public PostingTweetEvent(Tweet tweeet) { 9 | this.tweeet = tweeet; 10 | } 11 | 12 | public Tweet getTweeet() { 13 | return tweeet; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/jobs/FetchTweetsJob.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.jobs; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.birbit.android.jobqueue.CancelReason; 6 | import com.birbit.android.jobqueue.Job; 7 | import com.birbit.android.jobqueue.Params; 8 | import com.birbit.android.jobqueue.RetryConstraint; 9 | import com.birbit.android.jobqueue.examples.twitter.controllers.TwitterController; 10 | import com.birbit.android.jobqueue.examples.twitter.entities.Tweet; 11 | import com.birbit.android.jobqueue.examples.twitter.events.FetchedNewTweetsEvent; 12 | import com.birbit.android.jobqueue.examples.twitter.models.TweetModel; 13 | import org.greenrobot.eventbus.EventBus; 14 | import twitter4j.Status; 15 | import twitter4j.TwitterException; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | 21 | public class FetchTweetsJob extends Job { 22 | 23 | public FetchTweetsJob() { 24 | //use singleWith so that if the same job has already been added and is not yet running, 25 | //it will only run once. 26 | super(new Params(Priority.LOW).requireNetwork().groupBy("fetch-tweets").singleInstanceBy("fetch-tweets")); 27 | } 28 | 29 | @Override 30 | public void onAdded() { 31 | 32 | } 33 | 34 | @Override 35 | public void onRun() throws Throwable { 36 | TweetModel tweetModel = TweetModel.getInstance(); 37 | Tweet lastTweet = tweetModel.getLastTweet(); 38 | List statusList = TwitterController.getInstance().loadTweets(lastTweet == null ? null : lastTweet.getServerId()); 39 | if(statusList.size() > 0) { 40 | List tweets = new ArrayList(statusList.size()); 41 | for(Status status : statusList) { 42 | Tweet tweet = new Tweet(status); 43 | tweets.add(tweet); 44 | } 45 | tweetModel.insertOrReplaceAll(tweets); 46 | EventBus.getDefault().post(new FetchedNewTweetsEvent()); 47 | } 48 | } 49 | 50 | @Override 51 | protected void onCancel(@CancelReason int cancelReason, @Nullable Throwable throwable) { 52 | 53 | } 54 | 55 | @Override 56 | protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount, 57 | int maxRunCount) { 58 | if(throwable instanceof TwitterException) { 59 | //if it is a 4xx error, stop 60 | TwitterException twitterException = (TwitterException) throwable; 61 | int errorCode = twitterException.getErrorCode(); 62 | return errorCode < 400 || errorCode > 499 ? RetryConstraint.RETRY : RetryConstraint.CANCEL; 63 | } 64 | return RetryConstraint.RETRY; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/jobs/Priority.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.jobs; 2 | 3 | public class Priority { 4 | public static int LOW = 0; 5 | public static int MID = 500; 6 | public static int HIGH = 1000; 7 | } 8 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/models/DbHelper.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.models; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import com.birbit.android.jobqueue.examples.twitter.TwitterApplication; 6 | import com.birbit.android.jobqueue.examples.twitter.dao.DaoMaster; 7 | import com.birbit.android.jobqueue.examples.twitter.dao.DaoSession; 8 | import org.greenrobot.greendao.database.StandardDatabase; 9 | 10 | public class DbHelper { 11 | private static DbHelper instance; 12 | private DaoSession daoSession; 13 | private DaoMaster daoMaster; 14 | private SQLiteDatabase db; 15 | 16 | public synchronized static DbHelper getInstance() { 17 | if(instance == null) { 18 | instance = new DbHelper(); 19 | } 20 | return instance; 21 | } 22 | 23 | public DbHelper() { 24 | Context appContext = TwitterApplication.getInstance().getApplicationContext(); 25 | DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(appContext, "twitter", null); 26 | db = devOpenHelper.getWritableDatabase(); 27 | StandardDatabase standardDatabase = new StandardDatabase(db); 28 | daoMaster = new DaoMaster(standardDatabase, DaoMaster.SCHEMA_VERSION); 29 | daoSession = daoMaster.newSession(); 30 | } 31 | 32 | public DaoSession getDaoSession() { 33 | return daoSession; 34 | } 35 | 36 | public DaoMaster getDaoMaster() { 37 | return daoMaster; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/models/TweetModel.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.models; 2 | 3 | import com.birbit.android.jobqueue.examples.twitter.dao.TweetDao; 4 | import com.birbit.android.jobqueue.examples.twitter.entities.Tweet; 5 | 6 | import java.util.Collection; 7 | import org.greenrobot.greendao.query.LazyList; 8 | 9 | public class TweetModel { 10 | private static TweetModel instance; 11 | private TweetDao tweetDao; 12 | 13 | public synchronized static TweetModel getInstance() { 14 | if(instance == null) { 15 | instance = new TweetModel(); 16 | } 17 | return instance; 18 | } 19 | 20 | private TweetModel() { 21 | tweetDao = DbHelper.getInstance().getDaoSession().getTweetDao(); 22 | } 23 | 24 | public Tweet getLastTweet() { 25 | return tweetDao.queryBuilder().where(TweetDao.Properties.ServerId.isNotNull()) 26 | .orderDesc(TweetDao.Properties.CreatedAt) 27 | .limit(1).unique(); 28 | } 29 | 30 | public void insertOrReplace(Tweet tweet) { 31 | tweetDao.insertOrReplace(tweet); 32 | } 33 | 34 | public void insertOrReplaceAll(Collection tweets) { 35 | tweetDao.insertOrReplaceInTx(tweets); 36 | } 37 | 38 | public LazyList lazyLoadTweets() { 39 | return tweetDao.queryBuilder().orderDesc(TweetDao.Properties.IsLocal, TweetDao.Properties.CreatedAt).listLazy(); 40 | 41 | } 42 | 43 | public Tweet getTweetByLocalId(long localId) { 44 | return tweetDao.queryBuilder().where(TweetDao.Properties.LocalId.eq(localId)).limit(1).unique(); 45 | } 46 | 47 | public void deleteTweetById(long localId) { 48 | tweetDao.deleteByKey(localId); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/services/MyGcmJobService.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.services; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.birbit.android.jobqueue.JobManager; 6 | import com.birbit.android.jobqueue.examples.twitter.TwitterApplication; 7 | import com.birbit.android.jobqueue.scheduling.GcmJobSchedulerService; 8 | 9 | /** 10 | * Created by yboyar on 3/20/16. 11 | */ 12 | public class MyGcmJobService extends GcmJobSchedulerService { 13 | @NonNull 14 | @Override 15 | protected JobManager getJobManager() { 16 | return TwitterApplication.getInstance().getJobManager(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/services/MyJobService.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.services; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.birbit.android.jobqueue.JobManager; 6 | import com.birbit.android.jobqueue.scheduling.FrameworkJobSchedulerService; 7 | import com.birbit.android.jobqueue.examples.twitter.TwitterApplication; 8 | 9 | public class MyJobService extends FrameworkJobSchedulerService { 10 | @NonNull 11 | @Override 12 | protected JobManager getJobManager() { 13 | return TwitterApplication.getInstance().getJobManager(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/java/com/birbit/android/jobqueue/examples/twitter/tasks/SimpleBackgroundTask.java: -------------------------------------------------------------------------------- 1 | package com.birbit.android.jobqueue.examples.twitter.tasks; 2 | 3 | import android.app.Activity; 4 | import android.os.AsyncTask; 5 | 6 | import java.lang.ref.WeakReference; 7 | 8 | abstract public class SimpleBackgroundTask extends AsyncTask { 9 | WeakReference weakActivity; 10 | public SimpleBackgroundTask(Activity activity) { 11 | weakActivity = new WeakReference(activity); 12 | } 13 | @Override 14 | protected final T doInBackground(Void... voids) { 15 | return onRun(); 16 | } 17 | 18 | private boolean canContinue() { 19 | Activity activity = weakActivity.get(); 20 | return activity != null && activity.isFinishing() == false; 21 | } 22 | 23 | @Override 24 | protected void onPostExecute(T t) { 25 | if(canContinue()) { 26 | onSuccess(t); 27 | } 28 | } 29 | 30 | abstract protected T onRun(); 31 | 32 | abstract protected void onSuccess(T result); 33 | } 34 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/res/layout/list_tweet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /examples/twitter/TwitterClient/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | 20 |