java在子线程不处理异常,main线程还会继续执行;android在子线程不处理异常,会导致crash,进程会被杀死。
我在对android媒体库执行删除操作的时候,写法有问题,所以报了参数非法异常。
错误写法:
public void deleteMediaItem(MediaInfo mediaInfo) {
String where = MediaStore.MediaColumns.DATA + " = " + mediaInfo.getPath();
int recordRowsDeleted = mContentResolver.delete(FILE_URI, where, null);
LogUtils.d(TAG + " media recordRowsDeleted:" + recordRowsDeleted);
}
正确写法:
public void deleteMediaItem(MediaInfo mediaInfo) {
LogUtils.i(TAG + "deleteMediaItem: mediaInfo = " + mediaInfo);
String where = MediaStore.MediaColumns.DATA + "=?";
String[] selectionArgs = new String[]{mediaInfo.getPath()};
int recordRowsDeleted = mContentResolver.delete(FILE_URI, where, selectionArgs);
LogUtils.d(TAG + " media recordRowsDeleted:" + recordRowsDeleted);
}
在子线程中没有显式地处理异常
错误写法:
RxUtils.requestData(Observable.create(emitter -> {
for (RecordVideo recordVideo : recordVideoList) {
MediaInfo mediaInfo = mDataBaseManager.convertRecordToMediaInfo(recordVideo);
if (recordVideo.getR() != 1) {
mDataBaseManager.insertMediaItem(mediaInfo);
} else if (recordVideo.getR() == 1) {
mDataBaseManager.deleteMediaItem(mediaInfo);
}
}
emitter.onNext(0);
}), o -> {
LogUtils.d(TAG + "value:" + o);
});
正确写法:
RxUtils.requestData(Observable.create(emitter -> {
try {
List<MediaInfo> mediaInfoList = new ArrayList<>();
for (RecordVideo recordVideo : recordVideoList) {
MediaInfo mediaInfo = mDataBaseManager.convertRecordToMediaInfo(recordVideo);
if (recordVideo.getR() != 1) {
mediaInfoList.add(mediaInfo);
if (mediaInfoList.size() == Constants.GALLERY_NETWORK_SIZE_SMALL) {
int insertRows = mDataBaseManager.bulkInsertMediaItem(mediaInfoList);
LogUtils.d(TAG + "bulkInsert rows" + insertRows);
mediaInfoList.clear();
}
} else if (recordVideo.getR() == 1) {
mDataBaseManager.deleteMediaItem(mediaInfo);
}
}
if (mediaInfoList.size() > 0) {
int insertRows = mDataBaseManager.bulkInsertMediaItem(mediaInfoList);
LogUtils.d(TAG + "loadRecordVideos bulkInsert rows" + insertRows);
mediaInfoList.clear();
}
emitter.onNext(0);
} catch (Exception e) {
emitter.onError(e);
}
}), result -> {
LogUtils.d(TAG + "loadRecordVideos delete result:" + result);
}, error -> {
LogUtils.d(TAG + "loadRecordVideos delete error" + error);
});
java中子线程不处理异常,main线程还会继续执行;android中子线程不处理异常,程序却会崩溃。
重点:Android和Java的默认UncaughtExceptionHandler
在java中:
public static void main(String[] args) {
Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
System.out.println("Java getDefaultUncaughtExceptionHandler:" + uncaughtExceptionHandler);
}
Java getDefaultUncaughtExceptionHandler:null
在android中:
public void getDefaultUncaughtExceptionHandler(View view) {
Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Log.d("top huang", "Android getDefaultUncaughtExceptionHandler:" + uncaughtExceptionHandler);
}
Android getDefaultUncaughtExceptionHandler:com.android.internal.os.RuntimeInit$KillApplicationHandler@45c74
得出结论:java中没有默认的UncaughtExceptionHandler,android中有一个UncaughtExceptionHandler (RuntimeInit$KillApplicationHandler)
public class RuntimeInit {
...
/**
* Logs a message when a thread encounters an uncaught exception. By
* default, {@link KillApplicationHandler} will terminate this process later,
* but apps can override that behavior.
*/
private static class LoggingHandler implements Thread.UncaughtExceptionHandler {
public volatile boolean mTriggered = false;
@Override
public void uncaughtException(Thread t, Throwable e) {
//...打印log信息...
}
}
}
/**
* Handle application death from an uncaught exception. The framework
* catches these for the main threads, so this should only matter for
* threads created by applications. Before this method runs, the given
* instance of {@link LoggingHandler} should already have logged details
* (and if not it is run first).
*/
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
private final LoggingHandler mLoggingHandler;
/**
* Create a new KillApplicationHandler that follows the given LoggingHandler.
* If {@link #uncaughtException(Thread, Throwable) uncaughtException} is called
* on the created instance without {@code loggingHandler} having been triggered,
* {@link LoggingHandler#uncaughtException(Thread, Throwable)
* loggingHandler.uncaughtException} will be called first.
*
* @param loggingHandler the {@link LoggingHandler} expected to have run before
* this instance's {@link #uncaughtException(Thread, Throwable) uncaughtException}
* is being called.
*/
public KillApplicationHandler(LoggingHandler loggingHandler) {
this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
ensureLogging(t, e); //打印log
...
} catch (Throwable t2) {
...
} finally {
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid()); // 杀死当前进程
System.exit(10);
}
}
......
}
}
一般有三种UncaughtExceptionHandler:
UncaughtExceptionHandler种类 | 优先级 |
---|---|
线程私有的UncaughtExceptionHandler | 最高 |
ThreadGroup的UncaughtExceptionHandler | 其次 |
静态默认的UncaughtExceptionHandler | 最后 |
我们没有人为地处理异常,就会交给KillApplicationHandler进行处理,这样的话就会打印对应的异常日志,并且将该进程杀死。