1. JobIntentService crash fix
使用JobIntentService执行异常操作时,遇到一个crash:Caller no longer running, last stopped +25s437ms because: timed out while starting
。
Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:353)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by java.lang.SecurityException: Caller no longer running, last stopped +25s437ms because: timed out while starting
at android.os.Parcel.readException(Parcel.java:1942)
at android.os.Parcel.readException(Parcel.java:1888)
at android.app.job.IJobCallback$Stub$Proxy.dequeueWork(IJobCallback.java:191)
at android.app.job.JobParameters.dequeueWork(JobParameters.java:196)
at android.support.v4.app.JobIntentService$JobServiceEngineImpl.dequeueWork(JobIntentService.java:309)
at android.support.v4.app.JobIntentService.dequeueWork(JobIntentService.java:627)
at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:384)
at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:377)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
99% of our crashes are happening on Android O, with a large number of those users on Samsung devices
在Github上有同样的issues及解决办法:
1.1.1. SafeJobIntentService
package android.support.v4.app;
import android.os.Build;
import android.support.annotation.RestrictTo;
/**
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public abstract class SafeJobIntentService extends JobIntentService {
@Override
GenericWorkItem dequeueWork() {
try {
return super.dequeueWork();
} catch (SecurityException e) {
e.printStackTrace();
return null;
}
}
@Override
public void onCreate() {
super.onCreate();
// override mJobImpl with safe class to ignore SecurityException
if (Build.VERSION.SDK_INT >= 26) { // 如果Android版本大于等于O版本
mJobImpl = new SafeJobServiceEngineImpl(this);
} else {
mJobImpl = null;
}
}
}
1.1.2. SafeJobServiceEngineImpl
package android.support.v4.app;
import android.app.job.JobParameters;
import android.app.job.JobServiceEngine;
import android.app.job.JobWorkItem;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.util.Log;
/**
* Implementation of a JobServiceEngine for interaction with JobIntentService.
*/
@RequiresApi(26)
public class SafeJobServiceEngineImpl extends JobServiceEngine
implements JobIntentService.CompatJobEngine {
static final String TAG = "JobServiceEngineImpl";
static final boolean DEBUG = false;
final JobIntentService mService;
final Object mLock = new Object();
JobParameters mParams;
final class WrapperWorkItem implements JobIntentService.GenericWorkItem {
final JobWorkItem mJobWork;
WrapperWorkItem(JobWorkItem jobWork) {
mJobWork = jobWork;
}
@Override
public Intent getIntent() {
return mJobWork.getIntent();
}
@Override
public void complete() {
synchronized (mLock) {
if (mParams != null) {
try {
mParams.completeWork(mJobWork);
} catch (SecurityException se) {
// ignore
se.printStackTrace();
}
}
}
}
}
SafeJobServiceEngineImpl(JobIntentService service) {
super(service);
mService = service;
}
@Override
public IBinder compatGetBinder() {
return getBinder();
}
@Override
public boolean onStartJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStartJob: " + params);
mParams = params;
// We can now start dequeuing work!
mService.ensureProcessorRunningLocked(false);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStopJob: " + params);
boolean result = mService.doStopCurrentWork();
synchronized (mLock) {
// Once we return, the job is stopped, so its JobParameters are no
// longer valid and we should not be doing anything with them.
mParams = null;
}
return result;
}
/**
* Dequeue some work.
*/
@Override
public JobIntentService.GenericWorkItem dequeueWork() {
JobWorkItem work = null;
synchronized (mLock) {
if (mParams == null) {
return null;
}
try {
work = mParams.dequeueWork();
} catch (SecurityException se) {
// ignore it
se.printStackTrace();
}
}
if (work != null) {
work.getIntent().setExtrasClassLoader(mService.getClassLoader());
return new WrapperWorkItem(work);
} else {
return null;
}
}
}