yigit / android-priority-jobqueue

A Job Queue specifically written for Android to easily schedule jobs (tasks) that run in the background, improving UX and application stability.
3.4k stars 395 forks source link

java.lang.RuntimeException: cannot save job to disk Caused by: java.io.NotSerializableException: com.octo.android.robospice.SpiceManager #406

Closed marlene89 closed 7 years ago

marlene89 commented 7 years ago

Can you help me figure out what needs to be done? I am trying to queue SpiceManager requests from robospice library, but its failing with this error

java.lang.RuntimeException: cannot save job to disk at com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue.persistJobToDisk(SqliteJobQueue.java:107) at com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue.insert(SqliteJobQueue.java:90) at com.birbit.android.jobqueue.cachedQueue.CachedJobQueue.insert(CachedJobQueue.java:29) at com.birbit.android.jobqueue.JobManagerThread.handleAddJob(JobManagerThread.java:143) at com.birbit.android.jobqueue.JobManagerThread.access$100(JobManagerThread.java:35) at com.birbit.android.jobqueue.JobManagerThread$1.handleMessage(JobManagerThread.java:228) at com.birbit.android.jobqueue.messaging.PriorityMessageQueue.consume(PriorityMessageQueue.java:39) at com.birbit.android.jobqueue.JobManagerThread.run(JobManagerThread.java:222) at java.lang.Thread.run(Thread.java:762) Caused by: java.io.NotSerializableException: com.octo.android.robospice.SpiceManager at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1224) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346) at com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue$JavaSerializer.serialize(SqliteJobQueue.java:493) at com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue.persistJobToDisk(SqliteJobQueue.java:105) at com.birbit.android.jobqueue.persistentQueue.sqlite.SqliteJobQueue.insert(SqliteJobQueue.java:90)  at com.birbit.android.jobqueue.cachedQueue.CachedJobQueue.insert(CachedJobQueue.java:29)  at com.birbit.android.jobqueue.JobManagerThread.handleAddJob(JobManagerThread.java:143)  at com.birbit.android.jobqueue.JobManagerThread.access$100(JobManagerThread.java:35)  at com.birbit.android.jobqueue.JobManagerThread$1.handleMessage(JobManagerThread.java:228)  at com.birbit.android.jobqueue.messaging.PriorityMessageQueue.consume(PriorityMessageQueue.java:39)  at com.birbit.android.jobqueue.JobManagerThread.run(JobManagerThread.java:222)  at java.lang.Thread.run(Thread.java:762) 

Here is my DeleteSmsJob class ` public class DeleteSmsJob extends Job{ public SpiceManager spiceManager= new SpiceManager(ApiService.class); List messageIDs;

public DeleteSmsJob(List<String> messageIDs)
{
    // This job requires network connectivity,
    // and should be persisted in case the application exits before job is completed.
    super(new Params(100).requireNetwork().persist());
    this.messageIDs = messageIDs;
}

@Override
public void onAdded() {

}

@Override
public void onRun() throws Throwable {
    if (spiceManager == null){
        spiceManager = new SpiceManager(ApiService.class);
        spiceManager.start(getApplicationContext());
    }
    spiceManager.execute(new SetSmsDeletedFlagRequest(messageIDs, true), new BaseRequestListener<Void>(getApplicationContext()) {
        @Override
        public void onRequestSuccess(Void aVoid) {
            Log.i("Message(s) deleted on server");
        }
    });
}

@Override
protected void onCancel(int cancelReason, @Nullable Throwable throwable) {

}

@Override
protected RetryConstraint shouldReRunOnThrowable(@NonNull Throwable throwable, int runCount, int maxRunCount) {
    return null;
}

} `

maxime-kouemo commented 7 years ago

Caused by: java.io.NotSerializableException: com.octo.android.robospice.SpiceManager

Do you have another constructor for this class(DeleteSmsJob)?

marlene89 commented 7 years ago

no it is only the one constructor thats in there

public DeleteSmsJob(List<String> messageIDs) { // This job requires network connectivity, // and should be persisted in case the application exits before job is completed. super(new Params(100).requireNetwork().persist()); this.messageIDs = messageIDs; }

maxime-kouemo commented 7 years ago

1- Try converting the list of messages into a string before passing it. And then, when you are in the onRun() convert it back into the list of messsages before the rest of the deleting process. Hence, you will change your constructor and it will take a Strjng instead of a List of Strings.

2- Make sure your job class declaration is in a separate file.

3- Add a spiceManager attribute in your Job class declaration, and always instsnciate it.

I keep scrashing my head, why is it trying to persit the spiceManager?

marlene89 commented 7 years ago

@maxime-kouemo I have tried all your suggestions. still seeing the same error :(

maxime-kouemo commented 7 years ago

I have no idea why it tries to serialize the spice manager. I use reteofit 2 and I have not yet encountered this type of error.

kalpeshp0310 commented 7 years ago

@marlene89 It is trying to serialize your SpiceManager instance. Remember you are creating a new instance of it SpiceManager in your DeleteSmsJob, and SpiceManager doesn't implement Serializable instance. You would need to inject SpiceManager using Dependency Injection provided by library and make your SpiceManager instance transient so that job manager doesn't serializes it.

Example:

Add DependencyInjector in JobManager:

JobManager jobManager = new JobManager(
        new Configuration.Builder(context).injector(new com.birbit.android.jobqueue.di.DependencyInjector({
            @Override public void inject(Job job) {
                if (job instanceof DeleteSmsJob) {
                    ((DeleteSmsJob) job).spiceManager = new SpiceManager(ApiService.class);
                }
            }
        })).build());

Making SpiceManager instance transient:

public class DeleteSmsJob extends Job {
    public transient SpiceManager spiceManager;
    List messageIDs;
    //.....
}
maxime-kouemo commented 7 years ago

Try setting your spiceManager attribute to transient, as mentioned by @kalpeshp0310 .

marlene89 commented 7 years ago

That did the trick. Along with changing

    @Override
    public void onRun() throws Throwable {
        if (spiceManager == null){
            spiceManager = new SpiceManager(ApiService.class);
            spiceManager.start(getApplicationContext());
        }
        spiceManager.execute(new SetSmsDeletedFlagRequest(messageIDs, true), new BaseRequestListener<Void>(getApplicationContext()) {
            @Override
            public void onRequestSuccess(Void aVoid) {
                Log.i("Message(s) deleted on server");
            }
        });
    }

To:

 @Override
    public void onRun() throws Throwable {
        if (spiceManager == null){
            spiceManager = new SpiceManager(ApiService.class);
        }

        if(!spiceManager.isStarted())
        {
            spiceManager.start(getApplicationContext());
        }

        spiceManager.execute(new SetSmsDeletedFlagRequest(messageIDs, true), new BaseRequestListener<Void>(getApplicationContext()) {
            @Override
            public void onRequestSuccess(Void aVoid) {
                Log.i("Message(s) deleted on server");
            }
        });
    }

Otherwise SpiceManager will not be started. Thank you @kalpeshp0310 for your help. Much Appreciated.