在做项目时,无论为了功能还是调试,很多时候都需要获取到当前类的类名,包名,路径等等。
在这里总结一下,以便总结和以后需要的时候更快的解决问题。
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 。