patternjavaMinor
JSON loader with event bus, cache, and session
Viewed 0 times
loaderwithandbuscachesessionjsonevent
Problem
I have an Android application which needs to retrieve JSON files from a server and then display the information in my app. To accomplish this I have the following architecture:
While I was developing other parts of the application I simply provided the job queue, event bus and cache via constants, i.e.
I knew at some point I wanted to use dependency injection (via the Dagger 2 library) to improve the style and make my code more modular and testable. I have now begun the process of migrating my code over to this style but I am discovering some problems. Here is my new code (some parts omitted):
```
public class MainActivity extends Activity {
@Inject EventBus mEventBus;
@Inject JobQueue mJobQueue;
@Inject Cache mCache;
private Session mSession;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Dagger 2 injection
/
((MyApplication) getApplication()).getDependenciesComponent().inject(this);
final HttpUser httpUser = new HttpUser("xxxxxx@xxxxxxxx.com", "xxxxxxxx");
startSession(httpUser);
}
@Override
protected void onResume() {
super.onResume();
mEventBus.register(this);
}
@Override
protected void onPause() {
super.onPause();
mEventBus.unregister(this);
}
@Subscribe
public void onSessionStarted(final SessionStartedEvent sessio
- The main activity adds a job to the job queue requesting certain information from the server.
- The job gets run, retrieving the specified information and caching it in case the same request is made again in the future.
- The job on completion adds an event containing the information to the event bus.
- The event bus then relays the event back to the main activity which renders the information.
While I was developing other parts of the application I simply provided the job queue, event bus and cache via constants, i.e.
public class Dependencies {
public static final JobQueue JOB_QUEUE = new JobQueue();
public static final EventBus EVENT_BUS = new EventBus();
public static final Cache CACHE = new Cache();
}I knew at some point I wanted to use dependency injection (via the Dagger 2 library) to improve the style and make my code more modular and testable. I have now begun the process of migrating my code over to this style but I am discovering some problems. Here is my new code (some parts omitted):
```
public class MainActivity extends Activity {
@Inject EventBus mEventBus;
@Inject JobQueue mJobQueue;
@Inject Cache mCache;
private Session mSession;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Dagger 2 injection
/
((MyApplication) getApplication()).getDependenciesComponent().inject(this);
final HttpUser httpUser = new HttpUser("xxxxxx@xxxxxxxx.com", "xxxxxxxx");
startSession(httpUser);
}
@Override
protected void onResume() {
super.onResume();
mEventBus.register(this);
}
@Override
protected void onPause() {
super.onPause();
mEventBus.unregister(this);
}
@Subscribe
public void onSessionStarted(final SessionStartedEvent sessio
Solution
The solution I developed was to inject the dependencies into the job queue instead of the jobs. This way the injection only has to happen once and can be accomplished nicely using Dagger 2 (note: because I was using the android-priority-jobqueue library I had to wrap it in my own class to allow for this functionality).
This is my Dagger module:
Dagger component:
My wrapper class for the android-priority-jobqueue
I also have a new
(Notice the dependencies are provided in the
My translator job class
```
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.Params;
import com.birbit.android.jobqueue.RetryConstraint;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
class BirbitJob extends com.birbit.android.jobqueue.Job {
private final Job mJob;
private final Context mContext;
private final EventBus mEventBus;
private final AppCache mAppCache;
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority) {
this(job, context, eventBus, appCache, priority, null);
}
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority,
final String groupId) {
super(new Params(priority).requireNetwork().groupBy(groupId));
mJob = job;
mContext = context;
mEventBus = eventBus;
mAppCach
This is my Dagger module:
import android.app.Application;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
import com.treemetrics.taskmanager3.work.jobqueue.JobQueue;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AppModule {
private final Application mApplication;
public AppModule(final Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
@Provides
@Singleton
EventBus providesEventBus() {
return new EventBus();
}
@Provides
@Singleton
AppCache providesCache() {
return new AppCache();
}
@Provides
@Singleton
JobQueue providesJobQueue(final Application app, final EventBus bus, final AppCache cache) {
return new JobQueue(app, bus, cache);
}
}Dagger component:
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
void inject(MainActivity activity);
}My wrapper class for the android-priority-jobqueue
JobManager class which accepts the dependencies:import android.content.Context;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.JobManager;
import com.birbit.android.jobqueue.config.Configuration;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
public class JobQueue {
private static final int DEF_PRIORITY = 1;
private final Context mContext;
private final JobManager mJobManager;
private final EventBus mEventBus;
private final AppCache mAppCache;
public JobQueue(final Context context, final EventBus eventBus, final AppCache appCache) {
mContext = context;
final Configuration jobManagerConfig = new Configuration.Builder(context).build();
mJobManager = new JobManager(jobManagerConfig);
mEventBus = eventBus;
mAppCache = appCache;
}
public void addJob(final Job job) {
addJob(job, null);
}
public void addJob(final Job job, @Nullable final CharSequence groupId) {
final String groupIdStr = (groupId != null) ? groupId.toString() : null;
final BirbitJob birbitJob = getBirbitJob(job, DEF_PRIORITY, groupIdStr);
mJobManager.addJobInBackground(birbitJob);
}
private BirbitJob getBirbitJob(final Job job, final int priority, @Nullable final String groupId) {
return new BirbitJob(job, mContext, mEventBus, mAppCache, priority, groupId);
}
}I also have a new
Job interface which my JobQueue wrapper class accepts instead of the Job class from the android-priority-jobqueue library. These jobs when submitted to my new JobQueue get translated to "birbit jobs" (the job class which the library accepts) and have the dependencies injected into them at that time. Here is my new Job interface and the BirbitJob class which is used to translate my jobs into the jobs accepted by android-priority-jobqueue.(Notice the dependencies are provided in the
onRun method.)import android.content.Context;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
public interface Job {
void onRun(Context context, EventBus bus, AppCache cache) throws Throwable;
void onCancel(Throwable throwable, EventBus bus);
}My translator job class
BirbitJob:```
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.Params;
import com.birbit.android.jobqueue.RetryConstraint;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
class BirbitJob extends com.birbit.android.jobqueue.Job {
private final Job mJob;
private final Context mContext;
private final EventBus mEventBus;
private final AppCache mAppCache;
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority) {
this(job, context, eventBus, appCache, priority, null);
}
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority,
final String groupId) {
super(new Params(priority).requireNetwork().groupBy(groupId));
mJob = job;
mContext = context;
mEventBus = eventBus;
mAppCach
Code Snippets
import android.app.Application;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
import com.treemetrics.taskmanager3.work.jobqueue.JobQueue;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AppModule {
private final Application mApplication;
public AppModule(final Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
@Provides
@Singleton
EventBus providesEventBus() {
return new EventBus();
}
@Provides
@Singleton
AppCache providesCache() {
return new AppCache();
}
@Provides
@Singleton
JobQueue providesJobQueue(final Application app, final EventBus bus, final AppCache cache) {
return new JobQueue(app, bus, cache);
}
}import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
void inject(MainActivity activity);
}import android.content.Context;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.JobManager;
import com.birbit.android.jobqueue.config.Configuration;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
public class JobQueue {
private static final int DEF_PRIORITY = 1;
private final Context mContext;
private final JobManager mJobManager;
private final EventBus mEventBus;
private final AppCache mAppCache;
public JobQueue(final Context context, final EventBus eventBus, final AppCache appCache) {
mContext = context;
final Configuration jobManagerConfig = new Configuration.Builder(context).build();
mJobManager = new JobManager(jobManagerConfig);
mEventBus = eventBus;
mAppCache = appCache;
}
public void addJob(final Job job) {
addJob(job, null);
}
public void addJob(final Job job, @Nullable final CharSequence groupId) {
final String groupIdStr = (groupId != null) ? groupId.toString() : null;
final BirbitJob birbitJob = getBirbitJob(job, DEF_PRIORITY, groupIdStr);
mJobManager.addJobInBackground(birbitJob);
}
private BirbitJob getBirbitJob(final Job job, final int priority, @Nullable final String groupId) {
return new BirbitJob(job, mContext, mEventBus, mAppCache, priority, groupId);
}
}import android.content.Context;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
public interface Job {
void onRun(Context context, EventBus bus, AppCache cache) throws Throwable;
void onCancel(Throwable throwable, EventBus bus);
}import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.Params;
import com.birbit.android.jobqueue.RetryConstraint;
import com.treemetrics.taskmanager3.util.AppCache;
import com.treemetrics.taskmanager3.work.eventbus.EventBus;
class BirbitJob extends com.birbit.android.jobqueue.Job {
private final Job mJob;
private final Context mContext;
private final EventBus mEventBus;
private final AppCache mAppCache;
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority) {
this(job, context, eventBus, appCache, priority, null);
}
public BirbitJob(final Job job,
final Context context,
final EventBus eventBus,
final AppCache appCache,
final int priority,
final String groupId) {
super(new Params(priority).requireNetwork().groupBy(groupId));
mJob = job;
mContext = context;
mEventBus = eventBus;
mAppCache = appCache;
}
@Override
public void onAdded() {
}
@Override
public void onRun() throws Throwable {
mJob.onRun(mContext, mEventBus, mAppCache);
}
@Override
protected void onCancel(final int cancelReason, @Nullable final Throwable throwable) {
mJob.onCancel(throwable, mEventBus);
}
@Override
protected RetryConstraint shouldReRunOnThrowable(
@NonNull final Throwable throwable, final int runCount, final int maxRunCount) {
return RetryConstraint.CANCEL;
}
}Context
StackExchange Code Review Q#146026, answer score: 2
Revisions (0)
No revisions yet.