在做项目时,无论为了功能还是调试,很多时候都需要获取到当前类的类名,包名,路径等等。
在这里总结一下,以便总结和以后需要的时候更快的解决问题。
1.在当前类获取当前的类名:
strings.add(getClass().getName()); //base.activity.SplashActivity strings.add(getClass().toString()); //class base.activity.SplashActivity strings.add(getClass().getSimpleName()); //SplashActivity strings.add(getClass().getCanonicalName());//base.activity.SplashActivity strings.add(getClass().getTypeName());//base.activity.SplashActivity strings.add(getPackageName());//com.vkkk.kzb strings.add(getLocalClassName());//base.activity.SplashActivity LogUtils.iTag("类名测试",strings);
2.检测某ActivityUpdate是否在当前Task的栈顶(获取当前正在栈顶的任务)
public static boolean isTopActivy(String cmdName, Context context) { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(Integer.MAX_VALUE);//取个1 String cmpNameTemp = null; if (null != runningTaskInfos) { //获取栈顶activity信息 获取到的是完整路径名,而不是简化,简化的请用getSimpleName。 cmpNameTemp = runningTasks.get(0).topActivity.getClassName(); } if (null == cmpNameTemp) { return false; } return cmpNameTemp.equals(cmdName); }
1.在项目中,需要拦截当前崩溃的信息和当前acticity以便于后台统计。所以我在父类BaseActicity中初始化CrashUtils工具类:
CrashUtils工具类会打印Bug的具体信息,以供技术人员更好的发现和解决问题,在blankj工具库里面,直接调用就行
CrashUtils.init(new CrashUtils.OnCrashListener() { @Override public void onCrash(CrashUtils.CrashInfo crashInfo) { String str = crashInfo.toString(); LogUtils.eTag("崩溃拦截",str); SP.getInstance().setErr(str);//存储错误信息到本地 ActivityManager manager = (ActivityManager)application.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> runningTasks = manager .getRunningTasks(1); //获取栈顶Activity ActivityManager.RunningTaskInfo cinfo = runningTasks.get(0); ComponentName component = cinfo.topActivity; Log.e("崩溃拦截-当前类名方式一", component.getClassName()); String string2 = runningTasks.get(0).topActivity.getClassName(); Log.e("崩溃拦截-当前类名方式二", string2); //存储当前崩溃类名到本地,可用于统计崩溃次数等 SP.getInstance().setErrPagename(component.getClassName()); } });
2.在之前的项目中,使用的是Thread.UncaughtExceptionHandler 来捕捉异常信息,这个的实现也很简单
在其他类初始它就行了。这儿我用的kotlin
CrashCollectHandler.Companion.getInstance().init(app.getApplicationContext()); class CrashCollectHandler : Thread.UncaughtExceptionHandler { //处理非正常的线程中止 var mContext: Context? = null var mDefaultHandler: Thread.UncaughtExceptionHandler? = null companion object { val instance by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { CrashCollectHandler() } } fun init(pContext: Context) { this.mContext = pContext // 获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler() // 设置该CrashHandler为程序的默认处理器 Thread.setDefaultUncaughtExceptionHandler(this) } //当UncaughtException发生时会转入该函数来处理 override fun uncaughtException(t: Thread?, e: Throwable?) { if (!handleException(e)) { //如果用户没有处理则让系统默认的异常处理器来处理 if (t != null && e != null) mDefaultHandler?.uncaughtException(t, e) } else { try { //给Toast留出时间 Thread.sleep(2000) // AppInitData.appError(mContext, e.toString(), null) } catch (e: InterruptedException) { e.printStackTrace() } finally { // android.os.Process.killProcess(android.os.Process.myPid()) //杀死进程 AppUtils.exitApp() //app } } } fun handleException(ex: Throwable?): Boolean { if (ex == null) { return false } Thread { Looper.prepare() Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", Toast.LENGTH_SHORT).show() Looper.loop() }.start() //存储错误信息 SP.getInstance().err = ex.toString(); //收集设备参数信息 //collectDeviceInfo(mContext); //保存日志文件 //saveCrashInfo2File(ex); // 注:收集设备信息和保存日志文件的代码就没必要在这里贴出来了 //文中只是提供思路,并不一定必须收集信息和保存日志 //因为现在大部分的项目里都集成了第三方的崩溃分析日志,如`Bugly` 或 `啄木鸟等` //如果自己定制化处理的话,反而比较麻烦和消耗精力,毕竟开发资源是有限的 return true } }
扩展
之前用CrashUtils来捕获异常,获取类名时用了RunningTaskInfo,emmmm,还是自己慢慢试出来的,结果今天前辈直接用CrashUtils的方法就解决了,还是对源码的了解程度不够啊。
public static void initCrash(Context context) { CrashUtils.init(crashInfo -> { if (App.DEBUG) LogUtils.eTag("崩溃拦截", crashInfo.getThrowable()); AppCrashErrorMobile mobile = new AppCrashErrorMobile(); mobile.setDetailMessage(crashInfo.getThrowable().getMessage()); mobile.setStackTrace(crashInfo.getThrowable().getStackTrace()[0]); SP.getInstance().setErr(mobile); });
直接用crashInfo.getThrowable().getStackTrace()[0]获取为栈顶的崩溃类。
下面为实体类,其中使用stacktrace的getClassName获取类名,getLineNumber获取行号,getMethodName获取报错方法名。
import java.io.Serializable; /** * app错误实体 */ public class AppCrashErrorMobile implements Serializable { // private String time = DateUtil.getDateTimeSecond(TimeUtils.getNowMills(), DateUtil.DATE_TIME_FORMAT); //错误时间 private String detailMessage = ""; //错误详情 private StackTraceElement stackTrace; //堆栈列表 public String getDetailMessage() { return detailMessage; } public void setDetailMessage(String detailMessage) { this.detailMessage = detailMessage; } public StackTraceElement getStackTrace() { return stackTrace; } public void setStackTrace(StackTraceElement stackTrace) { this.stackTrace = stackTrace; } @Override public String toString() { String strMsg = /*"\n" + "错误时间:" + time +*/ "\n" + "错误详情:" + detailMessage; if (stackTrace != null) strMsg = "\n" + "错误目标类:" + stackTrace.getClassName() + "\n" + "错误目标行号:" + stackTrace.getLineNumber() + "\n" + "错误目标方法:" + stackTrace.getMethodName() + strMsg; return strMsg; }
这样简介明了,既然别人封装的方法,肯定考虑的比我们全面,以后还是得多阅读源码,灵活应用~
2021.3.11 CrashUtils在由于异步问题,有时候拦截的日志并不能成功写入,项目改回使用 Thread.UncaughtExceptionHandler 。