0

I'm currently using Firebase JobDispatcher to run a periodic check in the background using the service intent (registered on boot, install & update). This is working correctly, and it spawns it's own thread separate from the main thread, so I don't lock the UI, and it kills the thread properly so garbage collection doesn't become a problem.

I would also like to trigger this same exact work from the main thread in-app. The problem is that running a jobdispatcher onCreate triggers the job to run in the main UI thread, and not in a background thread. One of my functions can generate A LOT of objects, so even though it properly runs, it kills usability in the app because the GC never can get rid of all the junk.

How can I run an existing JobDispatcher job on demand from the main thread, but still in a separate thread?

Thanks so much for your help.

Edits for clarification of this specific usage

My particular case involves a first run, where UpdateNetworkerJob.class can take several minutes to run. The phoneHistoryCheck.GetLastCallChecked() function has a loop which makes several calls to Firebase, both retrieving and putting information.

9/12 Update

Subsequent runs are very quick, and AsyncTask can work. However I am finding I need a more robust solution and am currently looking at ThreadPoolExecutor. It's possible that the GetLastCallChecked() function is throwing too much at the Firebase Engine and it causing the main thread's calls to Firebase to be way down in the noise as it catches up. I'm working on sorting this part out.

Code in main thread to start the work:

FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(trackedContactListActivity.this));
        Job myJob = dispatcher.newJobBuilder()
                .setService(UpdateNetworkerJob.class)
                .setTag("UpdateNetworkerService")
                .setTrigger(Trigger.NOW)
                .setConstraints(
                        Constraint.ON_ANY_NETWORK
                )
                .build();

        dispatcher.mustSchedule(myJob);

UpdateNetworkerJob.class

public class UpdateNetworkerJob extends JobService {

private static final String TAG = "UpdateNetworkerJob";

@Override
public boolean onStartJob(final JobParameters params) {


    Log.d(TAG, "UpdateNetworkerJob is running with params: " + params);
    PhoneHistoryCheck phoneHistoryCheck = new PhoneHistoryCheck();
    phoneHistoryCheck.GetLastCallChecked(UpdateNetworkerJob.this);



    return false;
}

@Override
public boolean onStopJob(JobParameters params) {
    // Stop tracking these job parameters, as we've 'finished' executing.
    //sendMessage(MSG_COLOR_STOP, params.getJobId());
    Log.d(TAG, "on stop job: " + params);

    // Return false to drop the job.
    return false;
}
}
  • Your post says: _This is working correctly, and it spawns it's own thread_. Is that referring to `UpdateNetworkerJob`? I don't see where it's creating a worker thread. You also state: _The problem is that running a jobdispatcher onCreate triggers the job to run in the main UI thread, and not in a background thread_. The scheduled job is a `JobService`, which runs on the main thread, regardless of the thread that schedules it. You have to create your own JobService worker thread. See: [intro to the JobService docs](https://developer.android.com/reference/android/app/job/JobService.html) – Bob Snyder Sep 11 '17 at 20:16
  • Correct. My class which extends Broadcast Receiver is not included in the original question.There I run a similar FirebaseJobDispatcher, but it is registered in the manifest under the intents: BOOT_COMPLETED, PACKAGE_REPLACED, PACKAGE_ADDED. When run this way, I can see a separate thread for my application get spawned and killed in the Android Monitor. Those docs you point at mention "thread/handler/AsyncTask" being needed to offload work. Is that what you mean? So this follows the line of logic below-that I need to manually start a separate thread somehow. Thank you for your help. – Vince Anido Sep 11 '17 at 20:48
  • You can get the thread name with `Thread.currentThread().getName()`. Add that to some log output from `UpdateNetworkerJob`. I'm pretty confident it will be the main/UI thread, even when started from your BroadcastReceiver. Yes, you need to rework `UpdateNetworkerJob` to perform the long-duration processing in worker thread or AsyncTask. – Bob Snyder Sep 11 '17 at 20:58
  • Ah...OK. Will check that. So just seeing a second thread ID in Android Monitor doesn't guarantee it's actually separate? Sorry, I'm obviously new to this. Thank you VERY much for your help! – Vince Anido Sep 11 '17 at 21:07
  • I don't know what the second thread is. Pretty sure it's not your JobService. – Bob Snyder Sep 11 '17 at 21:09
  • I think now the separate drop down in Android Studio Monitor is a separate instance of the app started by the JobDispatcher. I'm trying to find documentation to back this suspicion up. – Vince Anido Sep 12 '17 at 16:06

2 Answers2

0

Please call your service intent from the doinBackground function of an Asynctask. Example is here : Asynctask documentation

you can control the Asynctask from your UI without holding the UI for results.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
Abhishek
  • 1,261
  • 1
  • 13
  • 30
  • So is this instead of using JobDispatcher? In that scenario, I would just take the functions I was triggering from the UpdateNetworkerJob.class and put them into an AsyncTask, right? – Vince Anido Sep 11 '17 at 18:16
  • One more followup question: Doesn't AsyncTask have limitations on how long things inside it can run? The first time these run in my application they can run for several minutes. – Vince Anido Sep 11 '17 at 18:17
  • @VinceAnido - Yes, technically you can take the functions from JobDispatcher and insert them directly into Asynctask. And AsyncTask can run for a few minutes, as it runs in Background and continues even if the main activity is destroyed. However to prevent multiple AsyncTasks from running at same time, you should do some checks in "onPreexecute" function of Asynctask to ensure only 1 task is running. – Abhishek Sep 12 '17 at 03:03
0

Doesn't AsyncTask have limitations on how long things inside it can run? The first time these run in my application they can run for several minutes.

You can find answers to your queries in Threading performance article.

When using AsyncTask, there are a few important performance aspects to keep in mind.

First, by default, an app pushes all of the AsyncTask objects it creates into a single thread. Therefore, they execute in serial fashion, and—as with the main thread—an especially long work packet can block the queue. For this reason, we suggest that you only use AsyncTask to handle work items shorter than 5ms in duration

HandlerThread and ThreadPoolExecutor provides other alternatives.

You can find example code of HandlerThread in this post:

Call Main thread from secondary thread in Android

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
  • This makes a lot of sense. I think I've successfully implemented AsyncTask for my functions, and things are much faster, but I'm still getting ANR popups when the first run happens. I can't yet tell if it's because I'm flooding the Firebase Engine's queue, or due to something else. I'll give this implementation a try to see if it solves my issues. – Vince Anido Sep 12 '17 at 15:56
  • If your application has a time-consuming initial setup phase, consider showing a splash screen or rendering the main view as quickly as possible, indicate that loading is in progress and fill the information asynchronously. In either case, you should indicate somehow that progress is being made, lest the user perceive that the application is frozen. ( From https://developer.android.com/training/articles/perf-anr.html) – Ravindra babu Sep 12 '17 at 17:17
  • This is a very good point. As I'm hacking the MVP together, I've de-prioritized the on boarding activity. Now is probably a good time to begin doing that. I do still need to solve this, but it will help to have it organized properly, rather than bolted onto my main activity. – Vince Anido Sep 12 '17 at 17:40
  • Try to split long running task during initialization into multiple shorts tasks if possible. – Ravindra babu Sep 12 '17 at 17:44