android产品研发(二十二)-->android实用调试技巧

转载请标明出处:一片枫叶的专栏

上一篇文章中我们讲解了android UI优化方面的知识。我们讲解了android中的include、marge、ViewStub标签,在使用这些标签时可以简化我们的布局文件,优化组件绘制流程;讲解了android中的过度绘制相关知识点,通过优化我们的App过度绘制可以提高App的UI绘制流程与性能;我们还讲解了App中一些UI优化的小tips。更多关于android UI优化方面的知识可以参考我的:android产品研发(二十一)–>android中的UI优化

本文我们将讲解android中的调试技巧。程序调试,是将编制的程序投入实际运行前,用手工或编译程序等方法进行测试,修正语法错误和逻辑错误的过程。这是保证计算机信息系统正确性的必不可少的步骤。在android开发过程中熟练的使用调试技巧是一个很重要的方面。android的调试技巧包括熟练使用android中的日志API,自定义android日志框架,通过gradle配置调试日志,android studio的调试技巧等等。通过对本文的学习我们能够对android中调试技巧有一个大概的了解。

android中的打印API:

我们首先来看一下android中提供的打印日志API:

android.util.Log.java

这个类比较常用的打印日志的方法有5个,这5个方法都会把日志打印到AndroidMonitor中,android中日志分为五个级别:

  • Log.v(tag,message); //verbose模式,打印最详细的日志
  • Log.d(tag,message); //debug级别的日志
  • Log.i(tag,message); //info级别的日志
  • Log.w(tag,message); //warn级别的日志
  • Log.e(tag,message); //error级别的日志

其中tag和message分别是两个String值.从android开发帮助文档中来看,tag和message的定义分别是:

tag:Used to identify the source of a log message. It usually identifies the class or activity where the log call occurs.

msg:The message you would like logged.

可看出tag用来标记log消息的源头的。而message则是这条log的内容.

  • 一个简单的Log API例子

Log demo代码:

/**
 * 按钮点击事件,打印各个级别的日志
 */
button6.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v(TAG, "this is a verbose log!!!");
                Log.d(TAG, "this is a debug log!!!");
                Log.i(TAG, "this is a info log!!!");
                Log.w(TAG, "this is a warning log!!!");
                Log.e(TAG, "this is a error log!!!");
            }
        });

好吧,我们点击按钮,看一下AndroidMonitor中的打印结果:

07-17 19:22:16.202 7530-7530/uuch.com.android_activityanim V/MainActivity: this is a verbose log!!!
07-17 19:22:16.202 7530-7530/uuch.com.android_activityanim D/MainActivity: this is a debug log!!!
07-17 19:22:16.202 7530-7530/uuch.com.android_activityanim I/MainActivity: this is a info log!!!
07-17 19:22:16.202 7530-7530/uuch.com.android_activityanim W/MainActivity: this is a warning log!!!
07-17 19:22:16.203 7530-7530/uuch.com.android_activityanim E/MainActivity: this is a error log!!!

通过这种android自身Log API打印日志的方式,是最常见的一种打印日志的,调试代码的方式,基本上所有的项目中你可能都会遇到这种日志代码,前面的一篇文章中我也分析了Log日志的部分源码,具体可参考我的:android源码解析之(六)–>Log

但是呢你会发现这时候打印的日志格式比较简陋,比如出现异常的时候我们想快速定位到代码在哪,这时候就比艰难了,所以下面我们讲一下自定义日志框架。

自定义android打印框架MLog:

前面我们发现使用Android原生的Log API打印的日志格式比较简陋,那么可不可以定制化的显示一些友好型的日志信息呢?答案是肯定的,在前面的文章中我介绍了一个自定义的日志框架MLog,可参考我的:github项目解析(五)–>android日志框架

关于MLog框架的使用方式,实现过程等已在文章中做过简单的介绍,这里就看一下其打印的日志格式:

自定义按钮点击事件:

  • 在Application中初始化MLog框架
/**
 * 传入为true,则表示执行打印操作,否则不显示日志
 */
MLog.init(true);

尽量可以在Application的onCreate方法中执行,这是App的进程起始方法。

  • 在源代码中执行打印日志的操作
/**
 * 自定义按钮的点击事件
 */
button6.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MLog.v(TAG, "this is a verbose log!!!");
                MLog.d(TAG, "this is a debug log!!!");
                MLog.i(TAG, "this is a info log!!!");
                MLog.w(TAG, "this is a warning log!!!");
                MLog.e(TAG, "this is a error log!!!");
            }
        });

在AndroidMoitor中打印的日志格式和内容:

这样我们在点击日志信息的时候就能够跳转到这条日志的代码打印位置,是不是很方便?而且如果觉得日志格式不是很好的话,还可以定制化展示奥。

比如:

怎么样?是不是很好看了?

具体如何实现自定义Log框架以及自定义实现Log的显示样式可以参考我的:github项目解析(五)–>android日志框架

大多时候我们的App都有测试环境和正式环境两种环境的,当切换环境的时候要求我们在测试环境打印日志,则正式环境屏蔽日志,通过代码也可以实现,但是比较麻烦,有没有一个比较简单的方法呢?答案是肯定的,可以通过配置gradle的方式配置在测试环境中打印日志,在正式环境中屏蔽日志打印操作。

gradle中配置正式测试打印框架:

我们知道在android开发过程中为了调试代码经常在代码中添加一些日志信息,但是正式环境是不需要这些日志信息的,而且过得日志打印操作也会对App的性能有影响。

一个比较好的办法就是在App的测试环境中打印日志信息,在正式环境中屏蔽日志信息,那么如何实现呢?通过代码么?通过代码也是可以实现的,但是这样显得太原始了,其实android studio的gradle插件已经提供了这样的功能。

那么如何通过gradle配置日志打印信息呢?

buildTypes {
        debug {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            //混淆
            minifyEnabled false
            //Zipalign优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //加载默认混淆配置文件
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
            //签名
            signingConfig signingConfigs.debug
        }
        release {
            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            //混淆
            minifyEnabled true
            //Zipalign优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //加载默认混淆配置文件
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
            //签名
            signingConfig signingConfigs.relealse
        }
    }

在android studio的module的gradle配置文件中,在buildTypes节点下可以配置自定义参数,这里我们在debug版本中定义LOG_DEBUG为true,在release版本中定义LOG_DEBUG为false。这样在编译的时候就会在gradle的编译类BuildConfig中生成成员变量:

LOG_DEBUG
  • 若是正式环境则LOG_DEBUG的值为false
  • 若是测试环境则LOG_DEBUG的值为true

所以这时候可以通过LOG_DEBUG变量的值控制日志是否打印。

/**
 * 在Application的onCreate方法中初始化MLog日志框架
 * 并根据apk环境判断是否显示日志信息
 */
if (BuildConfig.LOG_DEBUG == true) {
    MLog.init(true);
} else {
    MLog.init(false);
}

我们实现的MLog框架的init方法

  • 若传入的值为true,则表示执行日志打印操作,也就是可以显示日志信息。
  • 若传入的值为false,则表示不执行日志打印操作,也就是不显示日志信息。

这样我们就实现了在测试环境打印日志,在正式环境中屏蔽日志的操作。

android studio的调试技巧:

写代码的过程中不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?你是否知道求值调试,条件断点,日志断点,方法断点,异常断点等调试技巧么?下面我们将介绍一下android studio中的调试技巧。

调试基础

一般来说我们有两种办法调试一个debuggable的apk;

  • 设置好断点,然后用debug模式编译安装这个app;
  • 执行attach debugger to android process,即将debug进程添加到当前进程中。

一般比较常使用的debug方式是attach debugger to android process:

在执行按钮右侧两个的带有小虫子的按钮其实就是Attach Debugger to android process按钮。

我们可以在启动apk之后,直接下断点,然后attach process到指定进程,条件触发之后就可以直接进入调试模式。

断点调试

断点调试是最基本操作,基恩的断点调试有以下的几个常用的调试命令:

  • F5跳转内部执行
  • F6跳转下一步
  • F8跳转到下一个断点

如何添加断点?

直接在android studio中的java源代码左侧,想调试某一行代码的话,直接单击若左侧出现了一个小红圈,则说明断点已经添加好了:

当代码处于debug模式,并且执行到此处的时候就会卡住在这里。

执行断点调试

执行attach debugger to android process,当代码执行到含有断点的时候就可以将程序卡到断点的代码了:

这时候我们可以看到在该行代码中可以看到相应的局部变量值,执行F6走到下一步,执行F8,调试到下一个断点。

添加观察变量

在调试模式下,选择变量,并右击:

这时候选择Add to watches,就可以将变量添加到观察列表了。

表达式调试:Evaluate Expression

这个调试功能非常的实用,也是我最喜欢的功能,使用ctrl + u快捷键可以弹窗表达式调试弹窗:

这个功能非常实用,可以在断点处直接进入一个求值环境,在这里你可以执行任何你感兴趣的表达式可以在表达式调试弹窗中写任何java表达式,比如:

其他的比如在断点处有一个对象object,如果你要查看它的某个属性很简单,在Debug窗口就能看到,但是如果你想要执行它的某个方法看看结果是什么呢?借助这个可以实现。当然它的功能远不止这么多,相当于直接进入了一个 REPL环境,非常实用。

条件断点

假设你的断点在一个列表的循环里面,可是你只对这个列表的某一个元素感兴趣,只想在遇到这个元素的时候才断下来;你是一直人肉 F9 直到满足条件吗?条件断点就是满足这种需求的,顾名思义,在特定条件下的断点。使用起来也非常简单,在你的断点上鼠标右键会出现一个小窗口,写上条件即可。

其他断点调试方式

除了这里的求值断点,条件断点,还有日志断点,异常断点,方法断点等,具体的可自行google哈。

总结:

  • android默认提供了Log API实现对日志的打印功能;
  • 可以实现自定义日志框架,定制化显示日志样式,定制化配置是否显示日志等,可参考:android日志框架
  • 可以通过配置gradle,让测试环境中显示日志信息,在正式环境中不显示日志信息;
  • android studio提供了断点调试功能,包含了求值调试,条件断点,日志断点,方法断点,异常断点等等;

另外对产品研发技术,技巧,实践方面感兴趣的同学可以参考我的:

android产品研发(十二)–>App长连接实现

android产品研发(十三)–>App轮训操作

android产品研发(十四)–>App升级与更新

android产品研发(十五)–>内存对象序列化

android产品研发(十六)–>开发者选项

android产品研发(十七)–>Hybrid开发

android产品研发(十八)–>webview问题集锦

android产品研发(十九)–>android studio中的单元测试

android产品研发(二十)–>代码Review

android产品研发(二十一)–>android中的UI优化



本文以同步至github中:https://github.com/yipianfengye/androidProject,欢迎star和follow


时间: 2024-08-04 00:10:52

android产品研发(二十二)-->android实用调试技巧的相关文章

android产品研发(十二)-->App长连接实现

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android应用内页面跳转协议-scheme协议,通过该协议我们可以跳转至指定的Activity,并在该Activity中解析scheme用于跳转到指定的页面,我们可以利用scheme协议实现应用内页面跳转.H5页面与Native页面相互跳转.通知栏消息跳转相应页面等,具体可参考:android产品研发(十一)–>使用scheme实现页面跳转. 而本文中我们将讲解一下App的长连接实现.一般而言长连接已经是App的标配了,推送功能的实现基础

android产品研发(十六)-->开发者选项

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android中内存对象的序列化方式.由于android开发涉及到不同Activity的数据传递,对于基本数据类型数据的传递是没有问题的,但是一旦涉及到复杂数据类型,就需要将数据序列化以便传输,在文章中我们主要讲解了两种数据序列化的方式:实现Serializable接口和实现Parcelable接口,同时也比较了它们各自的优缺点和实现方式.具体关于内存对象序列化方面的知识可参考:android产品研发(十五)–>内存对象序列化 本文主要介绍A

android产品研发(十四)-->App升级与更新

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android app中的轮训操作,讲解的内容主要包括:我们在App中使用轮训操作的情景,作用以及实现方式等.一般而言我们使用轮训操作都是通过定时任务的形式请求服务器并更新用户界面,轮训操作都有一定的使用生命周期,即在一定的页面中启动轮操作,然后在特定的情况下关闭轮训操作,这点需要我们尤为注意,我们还介绍了使用Timer和Handler实现轮训操作的实例,更多关于App中轮训操作的信息,可参考我的:android产品研发(十三)–>App轮训

android产品研发(十五)-->内存对象序列化

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android app中的升级更新操作,app的升级更新操作算是App的标配了,升级操作就是获取App的升级信息,更新操作是下载,安装,更新app,其中我们既可以使用app store获取应用的升级信息,也可以在应用内通过请求本地服务器获取应用的升级信息,并通过与本地app的版本号对比判断应用是否需要升级. 升级信息是app更新的基础,只有我们的app的升级信息指明需要更新,我们才可以开始后续的更新操作–也就是下载安装更新app.这里强调一点

android产品研发(十九)-->android studio中的单元测试

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了webview中问题集锦,讲解了webview的性能优化.webview种入Cookie信息.activity退出的时候清除webview信息报错.如何通过java代码和js代码相互交互.webview如何下载文件以及腾讯的X5浏览服务等知识,这些都是我在使用webview中遇到的问题,难点,实践等,更多关于这些问题的说明,可以参考我的:android产品研发(十八)–>webview趟过的坑 本文我们将讲解如何在android studio

android产品研发(十)-->不使用静态变量保存数据

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了Android中的几种常见网络协议:xml,json,protobuf等,以及各自的优缺点,一般而言主要我们的App涉及到了网络传输都会有这方面的内容,具体可根据项目的需求确定各自的网络传输协议.这里可参考android产品研发(九)–>App网络传输协议 而本文讲解的其实并不是一个技术方面,而是一个android产品研发过程中的技巧:尽量不使用静态变量保存核心数据.这是为什么呢?这是因为android的进程并不是安全的,包括applicat

android产品研发(二十一)-->UI优化

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android产品研发过程中的代码Review.通过代码Review能够提高产品质量,增强团队成员之间的沟通,提高开发效率,所以良好的产品开发迭代过程中,代码Review是一个必不可少的步骤.那么如何进行代码Review呢?我们主要讲解了团队成员之间的代码Review,代码lint检查,开发规范等方面的知识点,更多关于代码Review相关的知识可参考我的:android产品研发(二十)–>代码Review 本文我们将讲解一下android U

android产品研发(十七)-->Hybird开发

转载请标明出处:一片枫叶的专栏 上一篇文章中我们介绍了android开发中经常会涉及到但又常常被忽视掉的开发者模式.主要讲解了包括如何打开手机的开发者模式,开发者模式中各个菜单的意义和作用,如何清除手机App数据,以及清除手机App数据具体清除那些数据等知识点,具体关于android中开发者模式的知识,可参考我的:android产品研发(十六)–>开发者选项 本文将介绍android中hybird开发相关的知识点.hybird开发实际上是混合开发的意思,这里的混合是H5开发与Native开发混合

android产品研发(十三)-->App轮训操作

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android app实现长连接的几种方式,各自的优缺点以及具体的实现,一般而言使用第三方的推送服务已经可以满足了基本的业务需求,当然了若是对技术有追求的可以通过NIO或者是MINA实现自身的长连接服务,但是自己实现的长连接服务一来比较复杂耗时比较多,而且可能过程中有许多坑要填,一般而言推荐使用第三方的推送服务,稳定简单,具体管理长连接部分的模块可参考:android产品研发(十二)–>App长连接实现. 而本文将讲解app端的轮训请求服务,