android新闻APP错误排查处理,Android app 全局异常统一处理

创建一个类,实现接口UncaughtExceptionHandler public class CrashHandler implements UncaughtExceptionHandler

实现接口的方法uncaughtException(Thread t, Throwable e),异常的处理就在这里,比如保存异常信息到 SD 卡,自定义错误弹出信息,自动退出。 @Override

public void uncaughtException(Thread t, Throwable e) {

//收集错误信息,保存到 sd 卡上

errorInfo2SD();

//弹出自定义的错误提醒

new Thread(new Runnable() {

@Override

public void run() {

Looper.prepare();

Toast.makeText(mContext, "UnCrashException", Toast.LENGTH_SHORT).show();

Looper.loop();

}

});

//杀掉进程,退出应用

Process.killProcess(Process.myPid());

System.exit(1);

}

CrashHandler 采用单例模式。 public class CrashHandler implements UncaughtExceptionHandler {

private static CrashHandler mInstance;

private CrashHandler() {

}

// 单例模式-懒汉

public static CrashHandler getInstance() {

if (mInstance == null) {

synchronized (CrashHandler.class) {

if (mInstance == null) {

mInstance = new CrashHandler();

}

}

}

return mInstance;

}

}

定义一个方法,用于把当前应用注册到系统的异常处理中,让系统知道由自定义的异常捕获器处理。 public void register(Context context) {

mContext = context;

Thread.setDefaultUncaughtExceptionHandler(this);

}

在 Application 中注册。 public class CrashHandlerApplication extends Application {

@Override

public void onCreate() {

super.onCreate();

CrashHandler.getInstance().register(getApplicationContext());

}

}

收集错误信息并保存到 SD 卡上。 //用于存储设备信息

private MapmInfo = new HashMap<>();

//格式化时间,作为Log文件名

private java.text.DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");

private void errorInfo2SD(Throwable e) {

PackageManager pm = mContext.getPackageManager();

try {

PackageInfo info = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);

// 获取版本信息

if (info != null) {

String versionName = TextUtils.isEmpty(info.versionName) ? "未设置版本名称" : info.versionName;

String versionCode = info.versionCode + "";

mInfo.put("versionName", versionName);

mInfo.put("versionCode", versionCode);

}

// 获取设备信息

Field[] fields = Build.class.getFields();

if (fields != null && fields.length > 0) {

for (Field field : fields) {

field.setAccessible(true);

mInfo.put(field.getName(), field.get(null).toString());

}

}

// 存储信息到 sd 卡指定目录

saveErrorInfo(e);

} catch (NameNotFoundException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

private void saveErrorInfo(Throwable e) {

StringBuffer stringBuffer = new StringBuffer();

for (Map.Entryentry : mInfo.entrySet()) {

String keyName = entry.getKey();

String value = entry.getValue();

stringBuffer.append(keyName + "=" + value + "\n");

}

stringBuffer.append("\n-----Crash Log Begin-----\n");

StringWriter stringWriter = new StringWriter();

PrintWriter writer = new PrintWriter(stringWriter);

e.printStackTrace(writer);

Throwable cause = e.getCause();

while (cause != null) {

cause.printStackTrace(writer);

cause = e.getCause();

}

writer.close();

String string = stringWriter.toString();

stringBuffer.append(string);

stringBuffer.append("\n-----Crash Log End-----");

String format = dateFormat.format(new Date());

String fileName = "crash-" + format + ".log";

if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

String path = mContext.getFilesDir() + File.separator + "crash";

File dir = new File(path);

if (!dir.exists()) {

dir.mkdirs();

}

FileOutputStream fou = null;

try {

fou = new FileOutputStream(new File(path, fileName));

fou.write(stringBuffer.toString().getBytes());

fou.flush();

} catch (FileNotFoundException e1) {

e1.printStackTrace();

} catch (IOException e1) {

e1.printStackTrace();

} finally {

try {

if (fou != null) {

fou.close();

}

} catch (IOException e1) {

e1.printStackTrace();

}

}

}

}

以上完成了异常的捕获并保存到 sd 卡上,等待 app 再次启动的时候,上传异常信息到服务器上。

保存到 sd 卡上的位置

SD 卡中拿到的 Log 信息 SUPPORTED_64_BIT_ABIS=[Ljava.lang.String;@58ff504

versionCode=1

BOARD=msm8939

BOOTLOADER=3.19.0.0000

TYPE=user

ID=MMB29M

TIME=1461124295000

BRAND=htc

SERIAL=HC4AZYC00984

HARDWARE=qcom

SUPPORTED_ABIS=[Ljava.lang.String;@abaed

CPU_ABI=arm64-v8a

RADIO=unknown

IS_DEBUGGABLE=false

MANUFACTURER=HTC

SUPPORTED_32_BIT_ABIS=[Ljava.lang.String;@c11fd17

TAGS=release-keys

CPU_ABI2=

UNKNOWN=unknown

USER=buildteam

FINGERPRINT=htc/htccn_chs_2/htc_a51dtul:6.0.1/MMB29M/738098.4:user/release-keys

HOST=ABM110

PRODUCT=htccn_chs_2

versionName=1.0

DISPLAY=MMB29M release-keys

MODEL=HTC D820u

DEVICE=htc_a51dtul

-----Crash Log Begin-----

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.CharSequence android.widget.TextView.getText()' on a null object reference

at cc.lijingbo.crashhandler.MainActivity$1.onClick(MainActivity.java:26)

at android.view.View.performClick(View.java:5232)

at android.view.View$PerformClick.run(View.java:21289)

at android.os.Handler.handleCallback(Handler.java:739)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:168)

at android.app.ActivityThread.main(ActivityThread.java:5885)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)

-----Crash Log End-----

通过以上 log , 可以看到因为 NullPointerException 造成的退出。原因是 MainActivity.java 的第 26 行造成的。

工程的 MainActivity 类的源码,可以看到获取 tv2 的时候因为没有实例化,造成的空指针 public class MainActivity extends AppCompatActivity {

private TextView tv1;

private TextView tv2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv1 = (TextView) findViewById(R.id.tv1);

tv1.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

Toast.makeText(MainActivity.this, tv2.getText().toString(), Toast.LENGTH_SHORT).show();

}

});

}

}

源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值