Android解决问题的思路

2023-11-07

1.前言

授人以鱼不如授人以渔,当向别人请教了问题且被解答了疑惑后,或许也想知道对方是如何思考,如何按照一定的的逻辑得出最终的答案。故想分享一下我这6年Android开发中是如何解决问题的,一家之言,请同学们多多指教。

2.指导性原则

第一点:遇到问题或代码报错,阅读源码是最高效方式

由于Android是开源系统,所以我们可以很方便地查看到源码,如果遇到代码运行不符合预期,或者是代码崩溃的问题,都可以定位到相应的代码位置,往上阅读代码梳理其逻辑然后分析原因,找到解决方案。

网上的解决方案始终是别人的,自己查看源码得到的方案才是印象最深刻的,也是收获最多的。

当Android Studio上无法往下继续追踪源码时,可去此网址阅读:AOSPXRef

第二点:新知识学习先找官方指导文档和代码示例

一个Android开发者需要熟记的网站:Android 开发者 | Android Developers (google.cn)

关于Android的知识点都可以在这个网站上找到,比如说你想了解Android四大组件中Activity的生命周期,那么可以在这里看到生命周期的最详细解释:了解 Activity 生命周期 | Android 开发者 | Android Developers (google.cn),相信里边的那张生命周期流程图在很多文章中都出现过。

代码示例:示例 | Android 开发者 | Android Developers (google.cn),或者直接查看Github上的代码示例仓库:Android · GitHub

官方文档永远是第一手信息的来源处,开发Android的人写的文档会将所有的知识点都列罗上去,并且还有一些注意事项,而这些注意事项中描述的内容往往就是开发中容易遇到的问题。

第三点:从过往的经验中找答案

人类之所以能够不断进步成为食物链顶端的物种,靠的就是知识的不断传承以及在此基础上的创新。

编程开发亦是如此,开发者应当维护两个知识库,一是新学习的内容及技巧库,二是问题库

每次新学习到的知识或者是技巧都记录到内容库中,当下一次遇到该知识点时在内容库中查找的效率肯定比你在百度中查找更快。

问题库则是记录何时遇到了什么问题,是如何解决的,关键代码段是什么,查阅了什么资料,最好把资料链接也记录下来。

古希腊哲学家赫拉克利特说过:人不能两次踏进同一条河流。而对于程序员则是,程序员尽量不要写两次一模一样的Bug.

第四点:面向百度编程

如上述3点都没有办法帮你解决问题,那只能是用搜索引擎查找答案了。由于众所周知的原因,使用google搜索是一件比较麻烦的事情。从个人经验来说,大多数的问题使用百度搜索也能解决。比如遇到报错问题,直接将报错异常粘贴到百度,大部分异常都有人遇到过并有相应的对策。

这里推荐一个可以访问的国外编程问答网站Stack Overflow ,有一些疑难杂症可以在这里找到答案,在百度上搜索小众问题时一般都是在这个网站上得到正确的解决方案。

不用过分迷恋google搜索,一是中文社区也有很多资料,能解决大部分问题;二是google搜索要将问题转换为英文才能得到精确的答案;三是找梯子始终是一件需要成本的事情,金钱或者时间。把它当成最后一个选项,是一个理智的选择。

3.最佳实践

3.1 查找报错原因

某日程序员小Q完成某项功能调试时,程序崩溃报如下错误。

2022-09-18 22:47:06.493 24957-24957/cn.pigdreams.ampmdemo E/dreams.ampmdem: Invalid ID 0x00000003.
2022-09-18 22:47:06.493 24957-24957/cn.pigdreams.ampmdemo D/AndroidRuntime: Shutting down VM
2022-09-18 22:47:06.494 24957-24957/cn.pigdreams.ampmdemo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: cn.pigdreams.ampmdemo, PID: 24957
    android.content.res.Resources$NotFoundException: String resource ID #0x3
        at android.content.res.Resources.getText(Resources.java:453)
        at android.widget.TextView.setText(TextView.java:6479)
        at cn.pigdreams.ampmdemo.MainActivity$3.onClick(MainActivity.java:72)
        at android.view.View.performClick(View.java:7570)
        at android.view.View.performClickInternal(View.java:7525)
        at android.view.View.access$3900(View.java:836)
        at android.view.View$PerformClick.run(View.java:28680)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:263)
        at android.app.ActivityThread.main(ActivityThread.java:8273)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
2022-09-18 22:47:06.561 24957-24957/cn.pigdreams.ampmdemo I/Process: Sending signal. PID: 24957 SIG: 9
    
  //报错处代码如下
       int i = 3;
       tvHello.setText(i);
Level3:遇到过记忆深刻,马上解决

依赖清晰的记忆和积累的众多经验迅速解决了,耗费时间15秒。

此乃宗师境界,非一朝一夕可达到,日积月累,反复记忆,终将达成。

Level2:遇到过但忘了解决方法

此乃略有小成之程序员,会遇到2个分支。

  • 有问题集:打开问题集,搜索关键字,找到对策和之前记录的详细原因。耗时1分钟
  • 无问题集:打开百度,复制报错代码,一条条查看网页,运气好查看第一个网页时勾起了曾经的记忆,马上想到了解决方案。耗时3分钟。
Level1:完全没遇到过,一头雾水

入门不久的小Q,因经验较少,遇到了这个报错,手足无措。

大部分程序员会直接使用指导性原则中的第四点:面向百度编程。

搜索一番,发现原来是TextView.setText()中设置了一个数字,导致了程序崩溃,解决方案就是将数字转换成字符串TextView.setText()String.valueOf(i)

而后心想:好的,问题解决了,快点继续开发下一个任务。

这种方式耗时大概在5分钟左右,但一周过后又忘了这茬了,然后就是重复重复又重复。

如果按照指导性原则走呢?

  • 因之前无问题集,无法从过往经验中找答案,那只能先阅读源码。

  • 从报错的位置往上追溯,一步步找到报错的地方。

  • 追溯到报错位置,发现setText()有好几个重载函数,一个接收字符参数,一个接收int参数(resid),出错的就是这个TextView中setText(@StringRes int resid)函数。

        /**
         * Sets the text to be displayed using a string resource identifier.
         *
         * @param resid the resource identifier of the string resource to be displayed
         *
         * @see #setText(CharSequence)
         *
         * @attr ref android.R.styleable#TextView_text
         */
        @android.view.RemotableViewMethod
        public final void setText(@StringRes int resid) {
            setText(getContext().getResources().getText(resid));
            mTextSetFromXmlOrResourceId = true;
            mTextId = resid;
        }
        
        //往下追踪到Resources类
            /**
         * Return the string value associated with a particular resource ID.  The
         * returned object will be a String if this is a plain string; it will be
         * some other type of CharSequence if it is styled.
         * {@more}
         *
         * @param id The desired resource identifier, as generated by the aapt
         *           tool. This integer encodes the package, type, and resource
         *           entry. The value 0 is an invalid identifier.
         *
         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
         *
         * @return CharSequence The string data associated with the resource, plus
         *         possibly styled text information.
         */
        @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
            CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
            if (res != null) {
                return res;
            }
            throw new NotFoundException("String resource ID #0x"
                    + Integer.toHexString(id));
        }
    
  • 定位到了抛异常的位置,原因就是Resources#getText()这个方法中res变量没获取到值为空。为什么会为空呢,其实注释已经说的比较清楚了。我们把注释放到Google 翻译一下

  返回与特定资源 ID 关联的字符串值。 如果这是一个纯字符串,则返回的对象将是一个字符串; 如果设置了样式,它将是其他类型的 CharSequence。 
  @param id 所需的资源标识符,由 aapt 工具生成。 此整数对包、类型和资源条目进行编码。 值 0 是无效标识符。
  @throws NotFoundException 如果给定的 ID 不存在,则抛出 NotFoundException。 
  @return CharSequence 与资源关联的字符串数据,以及可能带有样式的文本信息。

从注释中可以得到关键信息,就是传入的resid(资源ID)不存在,所以抛出了NotFoundException

这里又引入了一个新知识点,资源ID,其实参数(@StringRes int resid)中有个注解@StringRes也可以大概猜到这个参数需要传入一个字符串资源。

搜索一下这个注解的含义,这里这个注解可能是标红的不能往下追,按下全局搜索@StringRes,在androidx.annotation包中发现了这个注解。

/**
 * Denotes that an integer parameter, field or method return value is expected
 * to be a String resource reference (e.g. {@code android.R.string.ok}).
 */
@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
public @interface StringRes {
}
//继续翻译注解
表示整数参数、字段或方法返回值应为字符串资源引用(例如 android.R.string.ok)。

从例如android.R.string.ok可以联想到我们在项目中一直在使用的R.id.tv_hello等资源ID。

至此一条完整的知识链路就清晰了。因为设置了一个无效的资源ID导致程序崩溃->随意设置的数字并不是一个有效的资源ID->资源ID是像R.string.ok这样的样式。

  • 来验证一下猜想,我们找到R文件,看看里边资源ID的格式.资源ID在R文件中,路径为\app\build\intermediates\runtime_symbol_list\debug\R.txt

    nt string abc_shareactionprovider_share_with_application 0x7f0e0019
    int string abc_toolbar_collapse_description 0x7f0e001a
    int string app_name 0x7f0e001b
    int string appbar_scrolling_view_behavior 0x7f0e001c
    int string bottom_sheet_behavior 0x7f0e001d
    

    可见string类型映射的资源ID数值是以0x7f0e开头的一个整数,而小Q传入的是3,肯定在这个映射表里找不到。验证了3是无效的资源ID,所以程序崩溃了。

  • 把问题记录下来,包含发生的时间、解决方案、关键代码、涉及到的知识点等信息

这些步骤走完,至少需要30分钟,虽然有些源代码会无法继续追下去只能通过阅读注释来得到答案。但是在这个过程中,把程序崩溃的根本原因搞清楚了,也把涉及到的知识点都搞清楚了,以后再遇到这种崩溃问题脑海中就会浮现这一链条式的知识点。就算暂时忘了,看一下问题集又马上回想起来了。

这30分钟积累下来的就是精髓知识点,会慢慢地刻在脑海,变成条件反映般的肌肉记忆,是非常值得的。在重复过个学习的过程中,Level1就会不知不觉的升级到了Level3,解决问题会是极快的速度。

3.2 新功能需要使用新知识

小Q某天接到了一个使用Widget显示应用简要功能按钮的需求,关于这个Widget完全没有概念,平时也很少接触到。

小Q依旧上述原则,先找官方文档。找到了Widget的如下信息,知识了Widget的含义和类型。

在这里插入图片描述

然后再找代码示例,在上述指导文档中已经有部分代码贴出来了。完整的代码示例StackWidget会提示无法访问,其实这个示例就是在其源码中的Sample目录中,我们从源码网站中去找AOSPXRef。StackWidget所在的目录为development/samples/StackWidget/,网页路径为StackWidget。如遇到点不开的代码示例链接,都可去此链接的sample目录中找着。

按照示例代码写一个widget的工程demo进行测试,如遇到问题再查看文档与示例代码。

通过官方文档学习到的新知识是最完整最系统的,会比个人博客的介绍会更加全面一些。如想让知识点更加熟练,可搜索相关的教程查看。

4.总结

  • 遇到报错先阅读源码找根本原因与解决方案
    • 阅读源码时注释是关键部分
    • 如无法通过阅读源码解决,通过搜索引擎找答案
    • 优先查看StackOverflow的方案
  • 将问题与解决方案保存至问题录中
  • 遇到新知识点先看官方文档,再按照代码示例自己编程跑一遍demo。
  • 不要犯重复的错误两次以上
  • 维护知识库和问题录,随时记得更新

5.网站附录

网站 网站说明
AOSPXRef 查看Android的源代码
Android 开发 Android开发者中文官网
Android代码示例 Android代码示例集合页
Android · GitHub Android Github示例代码仓库
Stack Overflow 编程问答网站
Google 翻译 用来翻译源码中的注释
sample 开发者官网中不能点开的链接代码可在此找到
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android解决问题的思路 的相关文章

随机推荐

  • cp210x驱动运行不了怎么解决_「推荐」如何解决数位板驱动不运行

    推荐 如何解决数位板驱动不运行 板绘的盆友们是不是经常遇到数位板没有压感 每次重新开机以后就会显示数位板驱动程序未运行不能用 把数位板的程序重新卸载安装 重新开机又不能用 这是怎么回事呢 解决方法来了 这是一个驱动的bug 以下分享两个方法
  • 初识OpenGL (-)纹理过滤(Texture Filtering)

    1 OpenGL需要知道怎样将纹理像素 Texture Pixel 也叫Texel 映射到纹理坐标 纹理坐标 不依赖于分辨率 Resolution 它可以是任意浮点值 给模型顶点设置的那个数组 OpenGL以这个顶点的纹理坐标数据去查找纹理
  • 基于gradle创建springBoot web项目(idea版本)

    1 创建纯净基于gradle的项目 idea版本 我们不基于https start spring io 来创建项目 因为其中有很多配置是我们不需要的 第一步 FIle gt New gt Project 选择Gradle Home 地址 F
  • 高德地图api之兴趣点搜索

    除了定位basic map 我们现在探讨一下使用api中提供的搜索兴趣点服务和路线查找服务 高德地图的api提供了对千万级别的兴趣点的搜索 PoiSearch有几种方式 常用的有关键字搜索 类型搜索 关键字搜索 1定义PoiSearch类
  • 什么是实体关系图(ERD)?

    什么是实体关系图 ERD 转载自 https www visual paradigm com cn guide data modeling what is entity relationship diagram 数据库是软件系统中不可或缺的
  • 基于DTW动态时间规整算法的时间序列特征分类matlab仿真

    目录 1 算法仿真效果 2 MATLAB源码 3 算法概述 4 部分参考文献 1 算法仿真效果 matlab2022a仿真结果如下 lt
  • Python GUI 设计(二)—Widget组件详解

    本篇是关于Tkinter模块中的组件及其用法的介绍 涉及Label Button Entry组件 1 1 Label标签组件 Label组件是窗口中比较常用的组件 通常用来添加文字和图片 同时还可以定义文字和图片的排列方式 它的语法格式如下
  • TCP/IP网络编程(1)

    1 套接字 套接字是由操作系统提供的网络数据通信软件设备 即使对网络数据传输原理不了解 也能够使用套接字完成网络数据传输 为了与远程计算机进行数据传输 需要连接到英特网 套接字就是进行网络连接的工具 服务端 接收连接请求的套接字创建流程如下
  • Unity 报错 UnauthorizedAccessException: Access to the path“”is denied.

    根据能查到的各种解释综合分析 导致该报错出现的原因有以下几点 1 第一次文件写入操作未结束就进行了第二次操作 2 路径中的文件没有写入权限 3 当前用户无访问权限
  • 了解 GNU GPL/GNU LGPL/BSD/MIT/Apache协议

    文章来源 http iflonely com wordpress 2010 07 E4 BA 86 E8 A7 A3 gnu gplgnu lgplbsdmitapache E5 8D 8F E8 AE AE 越来越多的开发者与设计者希望将
  • ORM框架 Dapper

    一 介绍 Dapper是一款轻量级ORM工具 如果你在小的项目中 使用Entity Framework NHibernate 来处理大数据访问及关系映射 未免有点杀鸡用牛刀 你又觉得ORM省时省力 这时Dapper 将是你不二的选择 ORM
  • 黑盒测试中的决策表设计

    前言 在软件开发中 测试是不可或缺的一个环节 其中 黑盒测试是一种比较常用的测试方法 它强调测试人员不需要知道程序内部结构 只需根据程序规格说明书来设计测试用例进行测试 本文将介绍黑盒测试中的一种决策表设计方法 同时 我也为大家准备了一份软
  • 前端WebSocket详解

    websocket是H5才开始提供的一种在单个TCP连接上进行全双工通讯的协议 主要作用就是建立服务器和客户端的长连接能更好的节省服务器资源和带宽 服务器向浏览器推流实现实时通信 复制代码 和http一样 WebSocket也是应用层协议
  • mysql create trigger 触发器已存在

    1 CREATE TRIGGER 时显示触发器以存在 2 DROP TRIGGER IF EXISTS 也失败 解决 1 通过my ini 查到 datadir的路径 找到数据文件路径 2 找到相关数据库目录 删除相关触发器文件 如触发器名
  • eclipse_cpp 配置mingw

    1 MinGW 5 1 6的安装 首先下载 然后双击安装 过程如下 这一步如果你只想用Eclipse编译C C程序的话 只选上面三项即可 当然你可以都安装上 接下来就等着慢慢下载和安装吧 如果你的网速比较快的话 那么你是非常幸运的 2 配置
  • 宽度优先搜索(BFS)详解,以及双向广搜

    百度百科的官方解释 宽度优先搜索算法 又称广度优先搜索 是最简便的图的搜索算法之一 这一算法也是很多重要的图的算法的原型 Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想 其别名又叫BFS 属于一种盲
  • td 字典表_mysql常用字典表(完整版)

    本节内容 mysql数据库中的常用字典表 1 显示数据库列表 复制代码 代码示例 mysql gt show databases 说明 其中字典库是 information schema 其中常用字典表 INFORMATION SCHEMA
  • java 面向对象编程 --- 类及类的成员

    目录 学习面向对象内容的三条主线 面向过程与面向对象 面向过程 POP 与 面向对象 OOP 面向对象的三大特征 例子 人把大象装进冰箱 面向对象的思想概述 类和对象 面向对象的思想概述 Java类及类的成员 类的语法格式 创建Java自定
  • SqlServer千万级以上的数据表查询优化方案《冷热数据库分离》的思路

    1 是分库而不是分表 分表即需要考虑引入分表算法 又影响后续查询 2 热数据只占全部数据的一部分 因此每次优先查询热库 以下情况才查询冷库 a 当查询条件未命中 结果集为空 时 查询冷库 b 当查询条件部分命中时 查询冷库 3 为了区分部分
  • Android解决问题的思路

    1 前言 授人以鱼不如授人以渔 当向别人请教了问题且被解答了疑惑后 或许也想知道对方是如何思考 如何按照一定的的逻辑得出最终的答案 故想分享一下我这6年Android开发中是如何解决问题的 一家之言 请同学们多多指教 2 指导性原则 第一点