Android开发常见问题
安卓常见问题,Bug等以及解答,欢迎大家更新和指正!!!
Android 系统
防止OOM:
8.0之后对内存使用方式做了修改,这两个操作就可以避免全部的oom: minSdk 26 ndk {abiFilters 'arm64-v8a'}
Android 9 Http请求:Cleartext HTTP traffic to ... not permitted
方案1:改用https
方案2:targetSdkVersion 降到27以下
方案3:更改网络安全配置(1)
1.在res文件夹下创建一个xml文件夹,然后创建一个network_security_config.xml文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>2.接着,在AndroidManifest.xml文件下的application标签增加以下属性:
方案4:更改网络安全配置(2):直接在AndroidManifest.xml配置文件的标签中直接插入android:usesCleartextTraffic="true"
View 问题
TextView
singleLine过时了,使用lines代替。maxLines=“1”不能限制文本只显示一行
string资源字符串自定义部分文本颜色
EditText
Java代码中调用了setFilters,会覆盖布局中maxLength属性,除非同时设置了LengthFilter
InputType问题
布局中inputType和xml中设置setInputType()使用有差异:例:xml中inputType=number,代码中不是设置TYPE_XXX_VARIATION_YYY,而是要设置TYPE_CLASS_XXX | TYPE_XXXX_VARAITION_YYY
CheckBox
button属性失效问题
button对应的Selector drawable,把选中和未选中状态单独放到一个drawable中,不然和selected等混在一个文件会失效
RecyclerView
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position...
RecyclerView绑定的 List 对象在更新数据之前进行了 clear,而这时紧接着迅速上滑 RecyclerView,就会造成崩溃,属于RecyclerView内部异常。
RecyclerView在多层嵌套的内容中,即使设置了wrap_content或者match_parent,但是数据项还是只显示1行,Item高度也不是wrap_content
使用可以让RecyclerView显示全的控件进行包裹,推荐使用NestedScrollView。(本人在项目中遇到这个问题,Recyclerview外层是多层LinearLayout, CardView等布局,还要在外层加上下拉刷新的功能。网上多种解决方案都试过,也没有采用inflate(layoutId, null, false)加载Item的方法,因为封装过Adapter再改代价很大。最后的解决方案是:在RecyclerView外层布局包裹NestedScrollView,禁用RecyclerView滑动,使用NestedScrollView的滑动即可[本人使用的下拉刷新是SmartRefreshLayout,内部使用NestedScrollView可以正常滑动,问题解决])
ScrollView嵌套RecyclerView的显示不全,滑动卡顿,夺取了焦点导致页面启动时RecyclerView上方布局没显示问题
有问题的代码:
滑动卡顿问题:
RecyclerView夺取焦点问题:外层布局需要增加属性(但是某些时候这个属性不起作用)
RecyclerView夺取焦点问题解决方案2:ScrollView的直接子View使用
显示不全的问题:使用NestedScrollView代替ScrollView
//没有问题的代码:
LinearLayout嵌套RecyclerView的显示不全,滑动卡顿,夺取了焦点导致页面启动时RecyclerView上方布局没显示问题(真实情况应是ScrollView嵌套LinearLayout嵌套RecyclerView会出现)
附上之前出问题的代码(问题已经改了):
解决方案是在RecyclerView外包裹RelativeLayout。原因:ScrollView嵌套RecyclerView解决以及原理详解 文中提到LinearLayout和RelativeLayout测量的不同
DiffUtil.Callback RecyclerView动态更新/增减数据需要实现的类
部分(partial)绑定vs完整(full)绑定 payloads 参数 是一个从(notifyItemChanged(int, Object)或notifyItemRangeChanged(int, int, Object))里得到的合并list。 如果payloads list 不为空,那么当前绑定了旧数据的ViewHolder 和Adapter, 可以使用 payload的数据进行一次 高效的部分更新。 如果payload 是空的,Adapter必须进行一次完整绑定(调用两参方法)。
需要实现的方法:DiffUtil.Callback:public Object getChangePayload(int oldItemPosition, int newItemPosition), RecyclerView.Adapter:public void onBindViewHolder(VH holder, int position, List payloads)
ScrollView
滚动到顶部或者底部 :
scrollView.fullScroll(ScrollView.FOCUS_DOWN);滚动到底部
scrollView.fullScroll(ScrollView.FOCUS_UP);滚动到顶部
滚动到顶部的三种方式:
ViewPager
Item切换重建(主要是和Fragment搭配使用时,切换到第三个页面,第一个页面销毁)
通过setOffscreenPageLimit防止频繁销毁(setOffscreenPageLimit注释:设置当前page左右两侧应该被保持的page数量,超过这个限制,page会被销毁重建(只是销毁视图),onDestroy-onCreateView,但不会执行onDestroy。尽量维持这个值小,特别是有复杂布局的时候,因为如果这个值很大,就会占用很多内存,如果只有3-4页的话,可以全部保持active,可以保持page切换的顺滑
Tools命名空间的使用 xmlns:tools="http://schemas.android.com/tools"
tools命名空间中的各种XML属性,这些属性支持设计时功能(例如,在片段中显示哪种布局)或编译时行为(例如应用于XML资源的缩小模式)。构建应用程序时,构建工具会删除这些属性,因此不会影响APK大小或运行时行为。
错误处理属性
tools:ignore
用于:任何元素
使用者:Lint
此属性接受以逗号分隔的lint问题ID列表,用于忽略指定的错误
例如,忽略MissingTranslation错误:
tools:targetApi
用于:任何元素
使用者:Lint
此属性与@TargetApiJava代码中的注释相同 :它允许指定支持此元素的API级别(作为整数或代码名称)。
表名此元素(以及任何子元素)将仅在指定的API级别或更高级别上使用。用于阻止lint警告
例如,指定 GridLayout仅适用于API级别14及更高版本:
tools:locale
用于:
使用者:Lint,Android Studio编辑器
这告诉工具给定<resources>元素中的资源的默认语言/语言环境是什么(因为工具否则假定为英语),以避免来自拼写检查器的警告。该值必须是有效的 区域设置限定符。
例如,将其添加到values/strings.xml文件(默认字符串值),以指示用于默认字符串的语言是西班牙语而不是英语:
设计时视图属性——仅在Android Studio布局预览中可见的布局特征
tools: 代替 android:
tools: 代替 android:用于:
使用者:Android Studio布局编辑器
可以使用tools:前缀而不是Android框架中的android:任何<View>属性在布局预览中插入示例数据。当在App运行之前未填充属性的值,但你希望在布局预览中预先看到效果时,这非常有用。
例如,如果android:text属性值是在运行时设置的,或者你希望看到布局的值不同于默认值,则可以添加 tools:text以仅为布局预览指定一些文本。

图1.该tools:text属性将“Google Voice”设置为布局预览的值
你可以添加android:命名空间属性(在运行时使用)和匹配tools:属性(仅在布局预览中覆盖运行时属性)。或者仅使用tools:属性用于布局预览。例如:
tools:context
用于:任何根
使用者:Lint,Android Studio布局编辑器
此属性声明默认情况下此布局与哪个Activity相关联。比如导入View.onClick方法到次Activity。
tools:itemCount
用于:
使用者:Android Studio布局编辑器
对于给定的RecyclerView,此属性指定布局编辑器应在“ 预览”窗口中呈现的条目数 。
例如:
tools:layout
用于:
使用者:Android Studio布局编辑器
此属性声明你希望布局预览在Fragment内绘制的布局(因为布局预览无法执行通常应用布局的活动代码)。例如:
tools:listitem / tools:listheader / tools:listfooter
用于:( 及其子类,比如)
使用者:Android Studio布局编辑器
这些属性指定在列表的条目,页眉和页脚的布局预览中显示的布局。布局中的任何数据字段都填充了数字内容,例如“项目1”,以便列表项不重复。
例如:
tools:showIn
用于:布局根需要嵌入并一同显示预览的布局
使用者:Android Studio布局编辑器
此属性将会把当前布局嵌入其引用的布局一同显示预览。例如:
资源收缩属性
minifyEnabled 用来开启删除无用代码,比如没有引用到的代码
shrinkResources 用来开启删除无用资源,也就是没有被引用的文件(经过实测是drawable,layout,实际并不是彻底删除,而是保留文件名,但是没有内容,等等),但是因为需要知道是否被引用所以需要配合mififyEnable使用,只有当两者都为true的时候才会起到真正的删除无效代码和无引用资源的目的。例如:
tools:shrinkMode
用于:
使用者:资源缩减构建工具
此属性允许你指定构建工具是否应使用“安全模式”(保护安全并保留所有明确引用的资源以及可能通过调用动态 引用的资源[Resources.getIdentifier()](https://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)))或“严格模式”(仅保留资源)在代码或其他资源中明确引用)。
默认是使用安全模式(shrinkMode="safe")。要改为使用严格模式,需更改为shrinkMode="strict"到<resources>节点,如下所示:
启用严格模式时,你可能需要使用tools:keep 以保留已删除但实际需要的资源,并用于 tools:discard显式删除更多资源。
有关更多信息,请参阅 缩小资源。
tools:keep
用于:
使用者:资源缩减构建工具
此属性用于指定你需要保留的资源(通常是因为它们在运行时以间接方式引用,例如通过将动态生成的资源名称传递给 [Resources.getIdentifier()](https://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)))。
用法:在资源目录(例如,at res/raw/keep.xml)中使用<resources>标记创建XML文件, 并将要保留在tools:keep属性中的每个资源指定为以逗号分隔的列表。可以将星号字符用作通配符。例如:
tools:discard
用于:
使用者:资源缩减构建工具
此属性用于指定你需要手动丢弃的资源(通常是因为资源被引用但不会影响你的应用,或者因为Gradle插件错误地推断出资源被引用)。
用法:在资源目录(例如,at res/raw/keep.xml)中使用<resources>标记创建XML文件, 并将要保留在tools:discard属性中的每个资源指定为以逗号分隔的列表。可以将星号字符用作通配符。例如:
Style问题
declare-styleable
format可选项
Activity等系统组件
Activity切换时,短暂白屏问题,主要是启动singleTask或者singleInstance标志的Activity,同时关闭当前Activity,大概率出现这个问题
Activity theme加上 true 即可。
这个标志应该也可以 true ,然后onCreate应该需要去掉这个标志。
moveTaskToBack(boolean) 点返回键时,把App移到后台,而不是退出
参数为false——代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
参数为true——则忽略这个限制,任何activity都可以有效。
判断Activity是否是task根,Activity本身给出了相关方法:isTaskRoot()
把App移到后台,而不是退出,最简单无脑的使用方法:MainActivity,重写onBackPressed如下,即可实现
Activity设置为Dialog样式
方案:
Activity Theme设置为:
不使用true,而使用parent="@style/Theme.AppCompat.DayNight.Dialog"的原因是因为在页面上输入框会被软键盘遮住,软键盘不会顶起输入法
布局:android:minWidth或者android:layout_width设置为很大的dp,防止宽度太小的问题
防止点击空白处页面关闭,Activity中调用:
这个方案也有不完美的地方(应该算系统问题),布局较高,输入框靠下时,获取到焦点窗口上移时会被截断。但是不算大问题。
MainActivity打开新的Activity,因点击触发异常后(直接onCreate抛异常App会直接死掉),返回当前Activity时,Fragment重叠问题
新Activity强退,导致MainActivity重新走了生命周期(onCreate-onStart-onResume)Activity保存了Fragment状态,在onCreate中savedInstanceState!=null,里头保存了Fragment状态:
方案:
输入法遮挡输入框问题
通用解决方法:AndroidManifest中Activity的windowSoftInputMode属性来调整
通用解决方法无法解决,主要是自定义软键盘的情况
ScrollView中的EditText被自定义输入法遮挡:
ScrollView子控件最后增加一个空布局,比如Space,默认隐藏;界面显示后,计算Space高度:软键盘高度-输入框底部距离当前Activity窗口底部距离,>0时,就是有遮挡问题。
监听自定义软键盘弹出/隐藏,或者输入框是否获得焦点,如果软键盘弹出/输入框获得焦点,显示Space,调用nestedScrollView.scrollTo(0, space.getHeight()),解决遮挡问题;软键盘隐藏时,隐藏Space
Dialog宽度不够问题
Dialog布局外层包裹一层RelativeLayout即可。
Kotlin 专题
Kotlin data class 和 Gson, @parcelize问题
gson 扩展方法
@parcelize 需要在build.gradle android内设置属性
例子:
指定Java调用的类名,要用到注解 @file:JvmName(),放在package之前
也就是要写成这样,剩下的就直接改变代码里的类名就可以了。
@file:JvmName("Utils") 和 @file:JvmMultifileClass 一起使用的场景:
生成文档
Kotlin 的文档生成工具称为 Dokka。其使用说明请参见 Dokka README。
Dokka 有 Gradle、Maven 和 Ant 的插件,因此你可以将文档生成集成到你的构建过程中。
Last updated