异常是指在程序的运行过程中所出现的错误,这些错误会干扰到指令的正常执行,从而造成程序的异常退出,常见的场景如:文件找不到、网络连接错误、非法参数等等
在java中,所有的异常都继承于Throwable:
java异常程序无法处理的错误,表示运行应用程序中较严重问题
程序本身可以处理的异常,分为两类:
unchecked exception(非检查异常):也称运行时异常(RuntimeException),比如常见的NullPointerException、IndexOutOfBoundsException。对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。
checked exception(检查异常,编译异常):也称非运行时异常(运行时异常以外的异常就是非运行时异常),java编译器强制我们必须进行捕获处理,比如常见的IOExeption、SQLException、JSONException等等,对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过
异常和错误的区别:异常能被程序本身可以处理,错误是无法处理
为了方便我们对应用的优化,可以使用Android系统提供的 UncaughtExceptionHandler,对我们应用的错误进行收集
/**
* 全局异常处理
*/
public class GlobalExceptionCaught implements UncaughtExceptionHandler {
private Context mContext;
private static GlobalExceptionCaught mInstance;
private UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
// 存储设备信息
private Map mInfo = new HashMap<>();
// 日期格式
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
private GlobalExceptionCaught() {
}
public static GlobalExceptionCaught getInstance() {
if (mInstance == null) {
synchronized (GlobalExceptionCaught.class) {
mInstance = new GlobalExceptionCaught();
}
}
return mInstance;
}
/**
* @param context context
*/
public void init(Context context) {
mContext = context;
mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
// 对错误信息经常处理
if (handleException(e)) {
// 人为处理
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
// 1秒之后杀掉当前进程
Process.killProcess(Process.myPid());
System.exit(1);
} else {
// 未处理,调用系统的, 及弹出讨厌的程序崩溃框
if (mDefaultUncaughtExceptionHandler != null) {
mDefaultUncaughtExceptionHandler.uncaughtException(t, e);
}
}
}
/**
* 是否认自己理异常
*
* @param e 异常
* @return true 处理 false 未处理
*/
private boolean handleException(Throwable e) {
if (e != null) {
collectErrorInfo();
saveErrorInfo(e);
return true;
} else {
return false;
}
}
// 收集错误信息
private void collectErrorInfo() {
try {
PackageManager pm = mContext.getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
if (packageInfo != null) {
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;
mInfo.put("versionName", versionName);
mInfo.put("versionCode", versionCode + "");
}
Field[] fields = Build.class.getFields();
if (fields.length > 0) {
for (Field field : fields) {
field.setAccessible(true); // 信息全部可用
try {
mInfo.put(field.getName(), field.get(new Object()).toString());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
// 保存错误信息
private void saveErrorInfo(Throwable e) {
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry entry : mInfo.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
stringBuilder.append(key).append("=").append(value).append("\n");
}
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
e.printStackTrace(printWriter);
Throwable cause = e.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = e.getCause();
}
printWriter.close();
String result = writer.toString();
stringBuilder.append(result);
long curTime = System.currentTimeMillis();
String date = dateFormat.format(new Date());
String fileName = "crash-" + date + "-" + curTime + ".log";
// 判断是否有sd卡
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = "/sdcard/crash/";
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(path + fileName);
fileOutputStream.write(stringBuilder.toString().getBytes());
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
自定义一个类,继承Application类,复写onCreate()方法
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
GlobalExceptionCaught globalExceptionCaught = GlobalExceptionCaught.getInstance();
globalExceptionCaught.init(this);
}
}
在清单文件进行配置:
.......
1> 可以使用第三方的bug收集,如腾讯的bugly,友盟的bug统计.
2> 平时我们在测试阶段,方便我们找错,可以使用如下方法:
当应用程序出现错误时,我们打开一个exception显示界面,显示我们程序中出现的异常
异常示例图第一步: 声明全局异常处理类
public class ExceptionCaught implements UncaughtExceptionHandler {
private UncaughtExceptionHandler uncaughtExceptionHandler;
public ExceptionCaught(UncaughtExceptionHandler uncaughtExceptionHandler) {
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
ShowExceptionActivity.showException(ex);
if (uncaughtExceptionHandler != null) {
uncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
}
第二步:全局显示界面配置
/**
* 崩溃日志显示界面
*/
public class ShowExceptionActivity extends BaseActivity {
private TextView exceptionView;
public static void showException(Throwable throwable) {
App applicationContext = App.getInstance();
if (applicationContext != null && BuildConfig.DEBUG) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
throwable.printStackTrace(new PrintStream(byteArrayOutputStream));
String msg = new String(byteArrayOutputStream.toByteArray());
Intent intent = new Intent(applicationContext, ShowExceptionActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("msg", msg);
applicationContext.startActivity(intent);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_exception);
exceptionView = findViewById(R.id.show_exception_view);
handlerIntent(getIntent());
}
/**
* 处理异常
*/
private void handlerIntent(Intent intent) {
String msg = intent.getStringExtra("msg");
if (msg != null)
exceptionView.append(msg);
}
}
}
第三步:自定义类,继承Application类,复写onCreate()方法
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Thread.UncaughtExceptionHandler handler
= Thread.getDefaultUncaughtExceptionHandler();
ExceptionCaughtAdapter exceptionCaughtAdapter = new ExceptionCaughtAdapter(handler);
Thread.setDefaultUncaughtExceptionHandler(exceptionCaughtAdapter);
}
}
}
第三步:在android清单文件中进行配置
以上是我对android中异常的理解