Android开发中遇到的奇怪问题和解决方法_北京时间

重现的方法是:使用 RecyclerView 加官方下拉刷新的时候,如果绑定的 List 对象在更新数据之前进行了 clear,而这时用户紧接着迅速上滑 RV,就会造成崩溃,而且异常不会报到你的代码上,属于RV内部错误。

写这篇文章属于脑中一闪的一个念头,是想着把自己做项目中遇到的一些奇怪问题和解决办法分享出来。因为是现想,所以想到一个在更新一个吧。可能有理解错误的地方,望指出.

1、App的首次安装。

问题描述:在我们安装完成一个app时,在安装界面直接点击打开。我们进入了app的首页,这时我们按home键返回桌面,再点击应用图标,会发现没有直接进入首页,而是先进入了app的闪屏页,在进入首页。重复这一步一直如此。这时我们按back键返回,发现没有直接退回桌面,而是返回到之前打开的多个首页。但是如果一开始安装完我们不是直接打开,而是在桌面点击应用进入就不会这样了。

奇奇怪怪~~

记得当时我在应用市场下载了部分应用,也有一些有同样的问题。但是有些虽然重复打开,但双击退出程序将整个重复打开的关闭了。这确实也是一种方法,但是觉得不是最合理。

解决方法:

1、https://code.google.com/p/android/issues/detail?id=2373#c40

2、http://stackoverflow.com/questions/3042420/home-key-press-behaviour/4782423#4782423

我贴一下代码

if (!isTaskRoot()) {

Intent intent = getIntent();

String action = intent.getAction();

if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {

finish();

return;

}

}

2、Android自定义CheckBox

问题描述:曾经写过一个自定义CheckBox,结果运行在4.1的手机上消失不见了。。。你说郁闷不。写法如下:

<CheckBox

android:id="@+id/check_box"

style="@style/MyCheckBox"

android:layout_width="wrap_content"

android:layout_height="match_parent"/>

<style name="MyCheckBox" parent="Widget.AppCompat.CompoundButton.CheckBox">

<item name="android:button">@drawable/checkbox_selector</item>

</style>

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/icon_on" android:state_checked="true"/>

<!-- 设置选中图片 -->

<item android:drawable="@drawable/icon_off" android:state_checked="false"/>

<!-- 设置未选中图片 -->

</selector>

写法没有什么问题吧,但是就是不显示,凭空消失。当然如果我加上文字,就出来了,但是文字图片重叠。。。

最后谷歌出了原因:大致是说4.1.2版本中CompoundButton没有getCompoundPaddingXX。两个版本的计算方式不一样,4.1.2以上版本绘制文字时,会把图片的宽度和paddingXX的宽度加上,而4.1.2版本只计算设置的paddingLeft。

知道了原因,解决方法:

<style name="MyCheckBox" parent="Widget.AppCompat.CompoundButton.CheckBox">

<item name="android:button">@null</item>

<item name="android:paddingLeft">0dp</item>

<item name="android:drawableLeft">@drawable/checkbox_selector</item>

</style>

3、RecyclerView Bug

问题描述:这个是在友盟的错误分析中报的,错误信息如下:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{42fb7f40 position=11 id=-1, oldPos=-1, pLpos:-1 no parent}

at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4801)

at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4932)

at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913)

at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)

at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)

at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)

at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1193)

at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1043)

at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1552)

at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2649)

at android.view.View.dispatchTouchEvent(View.java:7706)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2224)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1954)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2074)

at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1521)

at android.app.Activity.dispatchTouchEvent(Activity.java:2569)

at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2022)

at android.view.View.dispatchPointerEvent(View.java:7886)

at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3967)

at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3846)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3462)

at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3431)

at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3538)

at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3439)

at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3595)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3462)

at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3431)

at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3439)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5552)

at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5532)

at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5503)

at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5632)

at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)

at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)

at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)

at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5605)

at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5651)

at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)

at android.view.Choreographer.doCallbacks(Choreographer.java:574)

at android.view.Choreographer.doFrame(Choreographer.java:542)

at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)

at android.os.Handler.handleCallback(Handler.java:733)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:136)

at android.app.ActivityThread.main(ActivityThread.java:5162)

at java.lang.reflect.Method.invokeNative(Native Method)

at java.lang.reflect.Method.invoke(Method.java:515)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)

从上面可以看到并没有报到我们自己的代码里面来,这就很尴尬了。老办法谷歌,找到了Drakeet大神的一篇博客,说到了我的心坎里。

https://drakeet.me/recyclerview-inconsistency-detected-invalid-item/

重现的方法是:使用 RecyclerView 加官方下拉刷新的时候,如果绑定的 List 对象在更新数据之前进行了 clear,而这时用户紧接着迅速上滑 RV,就会造成崩溃,而且异常不会报到你的代码上,属于RV内部错误。初次猜测是,当你 clear 了 list 之后,这时迅速上滑,而新数据还没到来,导致 RV 要更新加载下面的 Item 时候,找不到数据源了,造成 crash.

真是一样一样的,那么解决方法大神也提供了,就是在刷新,也就是 clear 的同时,让 RecyclerView 暂时不能够滑动,之后再允许滑动即可。代码就是在 RecyclerView 初始化的时候加上是否在刷新进而拦截手势:

mRecyclerView.setOnTouchListener(

new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

if (mIsRefreshing) {

return true;

} else {

return false;

}

}

}

);

当然如果觉得刷新时不能滑动可以用这种方案:

https://stackoverflow.com/questions/31759171/recyclerview-and-java-lang-indexoutofboundsexception-inconsistency-detected-in

public class WrapContentLinearLayoutManager extends LinearLayoutManager {

//... constructor

@Override

public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {

try {

super.onLayoutChildren(recycler, state);

} catch (IndexOutOfBoundsException e) {

Log.e("probe", "meet a IOOBE in RecyclerView");

}

}

}

使用:

RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view);

recyclerView.setLayoutManager(new WrapContentLinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false));

补充:但是这里要注意的是,禁止 RecycleView "下拉刷新" 和 "加载更多" 同时执行 。否则会报:

java.lang.IllegalStateException: Added View has RecyclerView as parent but view is not a real child. Unfiltered index:0

at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:7048)

at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7012)

at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7000)

at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1428)

at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)

at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578)

at com.jingzhao.shopping.customview.WrapContentLinearLayoutManager.onLayoutChildren(WrapContentLinearLayoutManager.java:27)<---这里

at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3260)

at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3069)

at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3518)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:598)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)

at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1692)

at android.widget.LinearLayout.onLayout(LinearLayout.java:1468)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)

at android.widget.FrameLayout.onLayout(FrameLayout.java:514)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)

at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)

at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)

at android.widget.FrameLayout.onLayout(FrameLayout.java:514)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2232)

at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1984)

at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1163)

at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6190)

at android.view.Choreographer$CallbackRecord.run(Choreographer.java:773)

at android.view.Choreographer.doCallbacks(Choreographer.java:586)

at android.view.Choreographer.doFrame(Choreographer.java:556)

at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:759)

at android.os.Handler.handleCallback(Handler.java:739)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:159)

at android.app.ActivityThread.main(ActivityThread.java:5540)

at java.lang.reflect.Method.invoke(Native Method)

at java.lang.reflect.Method.invoke(Method.java:372)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

可以做类似的处理:

if(swipeRefreshLayout.isRefreshing()){ return;}

4、华为部分设备不打印Log

部分的华为设备工程模式下log是关闭的

1、如果是华为手机,进入拨号界面输入:##2846579##进入页面设置。

2、如果是华为pad,进入计算器输入:()()2846579()()= 进入页面设置。

5、一些注意点

(1)平时为了给apk瘦身,我们会对图片进行有损或无损的压缩。那我平时有用到的一个有损压缩网站tinypng,但是切记我们的9图不要压缩,不然会有问题。(这里顺便分享一个做9图的在线工具http://inloop.github.io/shadow4android/)

(2)Android的透明主题需谨慎使用。

(3)for循环不要把获得数量的代码写在循环当中:for(int i = 0; i <= list.size(); i ++)

(4)ListView的如果其宽度或高度被设置为wrap_content,会有性能等问题。参见:http://stackoverflow.com/questions/4270278/layout-width-of-a-listview

6、RecyclerView自动滚动

之前碰到的一个奇怪问题:RecyclerView 嵌套 RecyclerView,结果内部的RecyclerView会自动的滑动至顶部。最终找到了解决方法:RecyclerView常见问题解决方案

https://blog.csdn.net/qiushi_1990/article/details/73551262

两种解决办法:

一、内部Recyclerview去除焦点,父布局里获得焦点。

recyclerview.setFocusableInTouchMode(false);recyclerview.requestFocus();

比如父布局的一个textview。

textview.setFocusableInTouchMode(true); textview.requestFocus();

二、内部的Recyclerview加

android:overScrollMode="never"

父布局覆盖子VIew获取焦点:

android:descendantFocusability="blocksDescendants"

当然不推荐使用RecyclerView 嵌套 RecyclerView这种写法了。。。

7、NumberFormatException

起因是Bugly上报了一个错误:

说是我格式化"0,00"这样的一个字符串。代码大致如下:

String.format("%.2f", number);

排除了格式字符串的问题后我就纳闷了。中间经过了大量的搜索。。。,发现是格式化的问题。也就是在不指定Locale时,是跟随系统语言。在法语、德语、意大利语的语言中,格式化小数是逗号的。所以解决方法:

String.format(Locale.CHINA, "%.2f", number);

8、SecurityException

在之前项目中做了6.0的动态权限后,Bugly报错如下:

更奇怪的是报错的全部都是6.0的手机。

查了一下,找到了问题。发现是6.0的一个bug,在部分6.0上CHANGE_NETWORK_STATE权限获取不到,那么只能去获取WRITE_SETTINGS这个权限了。这个问题已经在6.0.1修复了。附上链接地址,

https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0

既然是6.0的问题,我们可以对6.0进行单独处理。抛出异常处或者在使用CHANGE_NETWORK_STATE权限前跳转到系统设置页去设置。

if(Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {

if (!Settings.System.canWrite(context)) {

Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);

intent.setData(Uri.parse("package:" + context.getPackageName()));

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intent);

}

}

当然也可以参考这位兄弟的方法:Android 6 完美解决 WRITE_SETTINGS 权限设置问题

https://www.jianshu.com/p/0b880871b887

9、WebView中Http和Https加载问题

比如https页面加载http图片或者http页面加载https图片时图片显示不出来,原因是因为在Android 5.0开始WebView默认不允许加载http与https混合页面,

解决办法:

//https与http混合资源处理

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

}

当然最好还是不要混合,保持统一。

10、一些注意点

使用Glide时,注意对传入的Acticity与Fragment进行判断,避免传入已经销毁Acticity,造成IllegalArgumentException异常。可以参考这篇Glide类似You cannot start a load for a destroyed activity异常简单分析

https://blog.csdn.net/loners_/article/details/73521968

不要在Android的Application对象中缓存数据!

https://www.jianshu.com/p/83f0046bc310

在做6.0动态权限时,如果有申请相机权限时,应该保证Manifest.permission.CAMERA和Manifest.permission.WRITE_EXTERNAL_STORAGE权限同时申请,不要漏掉后者。

免费获取更多安卓开发架构的资料(包括Fultter、高级UI、性能优化、架构师课程、 NDK、混合式开发(ReactNative+Weex)和一线互联网公司关于android面试的题目汇总可以加:936332305 / 链接:点击链接加入【安卓开发架构】:https://jq.qq.com/?_wv=1027&k=515xp64

现代主义是人文主义的高级发展阶段。翔宇剧社排的剧挺现代的。我有点跟不上现代主义的步伐。 跟一个人讲不符合他的认知水平的知识,会对他造成不必要的痛苦。在看民主的黄昏这篇文章时,隐约感受到一个太监听别人讲纵欲的后果的痛苦。 我能不能以我的接受能力去要求其他的人?以我的接受能力,...

文 / 杨大侠 1 每年7月到9月 非洲北部的马拉河畔 都挤满了15万之多的斑马 它们来自塞伦盖蒂,来自马赛马拉 来自安博塞利,来自无数个早已干涸的东非高原 它们走过4000公里的漫长旅程 躲过狮群昼伏夜出的猛烈攻击 现在,它们不得不趟入水深流急的马拉河 进行波澜壮阔的史诗...

重现的方法是:使用 RecyclerView 加官方下拉刷新的时候,如果绑定的 List 对象在更新数据之前进行了 clear,而这时用户紧接着迅速上滑 RV,就会造成崩溃,而且异常不会报到你的代码上,属于RV内部错误。

写这篇文章属于脑中一闪的一个念头,是想着把自己做项目中遇到的一些奇怪问题和解决办法分享出来。因为是现想,所以想到一个在更新一个吧。可能有理解错误的地方,望指出.

1、App的首次安装。

问题描述:在我们安装完成一个app时,在安装界面直接点击打开。我们进入了app的首页,这时我们按home键返回桌面,再点击应用图标,会发现没有直接进入首页,而是先进入了app的闪屏页,在进入首页。重复这一步一直如此。这时我们按back键返回,发现没有直接退回桌面,而是返回到之前打开的多个首页。但是如果一开始安装完我们不是直接打开,而是在桌面点击应用进入就不会这样了。

奇奇怪怪~~

记得当时我在应用市场下载了部分应用,也有一些有同样的问题。但是有些虽然重复打开,但双击退出程序将整个重复打开的关闭了。这确实也是一种方法,但是觉得不是最合理。

解决方法:

1、https://code.google.com/p/android/issues/detail?id=2373#c40

2、http://stackoverflow.com/questions/3042420/home-key-press-behaviour/4782423#4782423

我贴一下代码

if (!isTaskRoot()) {

Intent intent = getIntent();

String action = intent.getAction();

if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {

finish();

return;

}

}

2、Android自定义CheckBox

问题描述:曾经写过一个自定义CheckBox,结果运行在4.1的手机上消失不见了。。。你说郁闷不。写法如下:

<CheckBox

android:id="@+id/check_box"

style="@style/MyCheckBox"

android:layout_width="wrap_content"

android:layout_height="match_parent"/>

<style name="MyCheckBox" parent="Widget.AppCompat.CompoundButton.CheckBox">

<item name="android:button">@drawable/checkbox_selector</item>

</style>

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/icon_on" android:state_checked="true"/>

<!-- 设置选中图片 -->

<item android:drawable="@drawable/icon_off" android:state_checked="false"/>

<!-- 设置未选中图片 -->

</selector>

写法没有什么问题吧,但是就是不显示,凭空消失。当然如果我加上文字,就出来了,但是文字图片重叠。。。

最后谷歌出了原因:大致是说4.1.2版本中CompoundButton没有getCompoundPaddingXX。两个版本的计算方式不一样,4.1.2以上版本绘制文字时,会把图片的宽度和paddingXX的宽度加上,而4.1.2版本只计算设置的paddingLeft。

知道了原因,解决方法:

<style name="MyCheckBox" parent="Widget.AppCompat.CompoundButton.CheckBox">

<item name="android:button">@null</item>

<item name="android:paddingLeft">0dp</item>

<item name="android:drawableLeft">@drawable/checkbox_selector</item>

</style>

3、RecyclerView Bug

问题描述:这个是在友盟的错误分析中报的,错误信息如下:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{42fb7f40 position=11 id=-1, oldPos=-1, pLpos:-1 no parent}

at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4801)

at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4932)

at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913)

at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)

at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)

at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)

at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1193)

at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1043)

at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1552)

at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2649)

at android.view.View.dispatchTouchEvent(View.java:7706)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2224)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1954)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230)

at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1968)

at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2074)

at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1521)

at android.app.Activity.dispatchTouchEvent(Activity.java:2569)

at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2022)

at android.view.View.dispatchPointerEvent(View.java:7886)

at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3967)

at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3846)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3462)

at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3431)

at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3538)

at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3439)

at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3595)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3462)

at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3431)

at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3439)

at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3412)

at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5552)

at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5532)

at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5503)

at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5632)

at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)

at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)

at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)

at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5605)

at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5651)

at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)

at android.view.Choreographer.doCallbacks(Choreographer.java:574)

at android.view.Choreographer.doFrame(Choreographer.java:542)

at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)

at android.os.Handler.handleCallback(Handler.java:733)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:136)

at android.app.ActivityThread.main(ActivityThread.java:5162)

at java.lang.reflect.Method.invokeNative(Native Method)

at java.lang.reflect.Method.invoke(Method.java:515)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)

从上面可以看到并没有报到我们自己的代码里面来,这就很尴尬了。老办法谷歌,找到了Drakeet大神的一篇博客,说到了我的心坎里。

https://drakeet.me/recyclerview-inconsistency-detected-invalid-item/

重现的方法是:使用 RecyclerView 加官方下拉刷新的时候,如果绑定的 List 对象在更新数据之前进行了 clear,而这时用户紧接着迅速上滑 RV,就会造成崩溃,而且异常不会报到你的代码上,属于RV内部错误。初次猜测是,当你 clear 了 list 之后,这时迅速上滑,而新数据还没到来,导致 RV 要更新加载下面的 Item 时候,找不到数据源了,造成 crash.

真是一样一样的,那么解决方法大神也提供了,就是在刷新,也就是 clear 的同时,让 RecyclerView 暂时不能够滑动,之后再允许滑动即可。代码就是在 RecyclerView 初始化的时候加上是否在刷新进而拦截手势:

mRecyclerView.setOnTouchListener(

new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

if (mIsRefreshing) {

return true;

} else {

return false;

}

}

}

);

当然如果觉得刷新时不能滑动可以用这种方案:

https://stackoverflow.com/questions/31759171/recyclerview-and-java-lang-indexoutofboundsexception-inconsistency-detected-in

public class WrapContentLinearLayoutManager extends LinearLayoutManager {

//... constructor

@Override

public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {

try {

super.onLayoutChildren(recycler, state);

} catch (IndexOutOfBoundsException e) {

Log.e("probe", "meet a IOOBE in RecyclerView");

}

}

}

使用:

RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view);

recyclerView.setLayoutManager(new WrapContentLinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false));

补充:但是这里要注意的是,禁止 RecycleView "下拉刷新" 和 "加载更多" 同时执行 。否则会报:

java.lang.IllegalStateException: Added View has RecyclerView as parent but view is not a real child. Unfiltered index:0

at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:7048)

at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7012)

at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7000)

at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1428)

at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)

at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578)

at com.jingzhao.shopping.customview.WrapContentLinearLayoutManager.onLayoutChildren(WrapContentLinearLayoutManager.java:27)<---这里

at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3260)

at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3069)

at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3518)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:598)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)

at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1692)

at android.widget.LinearLayout.onLayout(LinearLayout.java:1468)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)

at android.widget.FrameLayout.onLayout(FrameLayout.java:514)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)

at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)

at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)

at android.widget.FrameLayout.onLayout(FrameLayout.java:514)

at android.view.View.layout(View.java:15697)

at android.view.ViewGroup.layout(ViewGroup.java:5050)

at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2232)

at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1984)

at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1163)

at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6190)

at android.view.Choreographer$CallbackRecord.run(Choreographer.java:773)

at android.view.Choreographer.doCallbacks(Choreographer.java:586)

at android.view.Choreographer.doFrame(Choreographer.java:556)

at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:759)

at android.os.Handler.handleCallback(Handler.java:739)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:159)

at android.app.ActivityThread.main(ActivityThread.java:5540)

at java.lang.reflect.Method.invoke(Native Method)

at java.lang.reflect.Method.invoke(Method.java:372)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

可以做类似的处理:

if(swipeRefreshLayout.isRefreshing()){ return;}

4、华为部分设备不打印Log

部分的华为设备工程模式下log是关闭的

1、如果是华为手机,进入拨号界面输入:##2846579##进入页面设置。

2、如果是华为pad,进入计算器输入:()()2846579()()= 进入页面设置。

5、一些注意点

(1)平时为了给apk瘦身,我们会对图片进行有损或无损的压缩。那我平时有用到的一个有损压缩网站tinypng,但是切记我们的9图不要压缩,不然会有问题。(这里顺便分享一个做9图的在线工具http://inloop.github.io/shadow4android/)

(2)Android的透明主题需谨慎使用。

(3)for循环不要把获得数量的代码写在循环当中:for(int i = 0; i <= list.size(); i ++)

(4)ListView的如果其宽度或高度被设置为wrap_content,会有性能等问题。参见:http://stackoverflow.com/questions/4270278/layout-width-of-a-listview

6、RecyclerView自动滚动

之前碰到的一个奇怪问题:RecyclerView 嵌套 RecyclerView,结果内部的RecyclerView会自动的滑动至顶部。最终找到了解决方法:RecyclerView常见问题解决方案

https://blog.csdn.net/qiushi_1990/article/details/73551262

两种解决办法:

一、内部Recyclerview去除焦点,父布局里获得焦点。

recyclerview.setFocusableInTouchMode(false);recyclerview.requestFocus();

比如父布局的一个textview。

textview.setFocusableInTouchMode(true); textview.requestFocus();

二、内部的Recyclerview加

android:overScrollMode="never"

父布局覆盖子VIew获取焦点:

android:descendantFocusability="blocksDescendants"

当然不推荐使用RecyclerView 嵌套 RecyclerView这种写法了。。。

7、NumberFormatException

起因是Bugly上报了一个错误:

说是我格式化"0,00"这样的一个字符串。代码大致如下:

String.format("%.2f", number);

排除了格式字符串的问题后我就纳闷了。中间经过了大量的搜索。。。,发现是格式化的问题。也就是在不指定Locale时,是跟随系统语言。在法语、德语、意大利语的语言中,格式化小数是逗号的。所以解决方法:

String.format(Locale.CHINA, "%.2f", number);

8、SecurityException

在之前项目中做了6.0的动态权限后,Bugly报错如下:

更奇怪的是报错的全部都是6.0的手机。

查了一下,找到了问题。发现是6.0的一个bug,在部分6.0上CHANGE_NETWORK_STATE权限获取不到,那么只能去获取WRITE_SETTINGS这个权限了。这个问题已经在6.0.1修复了。附上链接地址,

https://stackoverflow.com/questions/32185628/connectivitymanager-requestnetwork-in-android-6-0

既然是6.0的问题,我们可以对6.0进行单独处理。抛出异常处或者在使用CHANGE_NETWORK_STATE权限前跳转到系统设置页去设置。

if(Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {

if (!Settings.System.canWrite(context)) {

Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);

intent.setData(Uri.parse("package:" + context.getPackageName()));

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intent);

}

}

当然也可以参考这位兄弟的方法:Android 6 完美解决 WRITE_SETTINGS 权限设置问题

https://www.jianshu.com/p/0b880871b887

9、WebView中Http和Https加载问题

比如https页面加载http图片或者http页面加载https图片时图片显示不出来,原因是因为在Android 5.0开始WebView默认不允许加载http与https混合页面,

解决办法:

//https与http混合资源处理

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

}

当然最好还是不要混合,保持统一。

10、一些注意点

使用Glide时,注意对传入的Acticity与Fragment进行判断,避免传入已经销毁Acticity,造成IllegalArgumentException异常。可以参考这篇Glide类似You cannot start a load for a destroyed activity异常简单分析

https://blog.csdn.net/loners_/article/details/73521968

不要在Android的Application对象中缓存数据!

https://www.jianshu.com/p/83f0046bc310

在做6.0动态权限时,如果有申请相机权限时,应该保证Manifest.permission.CAMERA和Manifest.permission.WRITE_EXTERNAL_STORAGE权限同时申请,不要漏掉后者。

免费获取更多安卓开发架构的资料(包括Fultter、高级UI、性能优化、架构师课程、 NDK、混合式开发(ReactNative+Weex)和一线互联网公司关于android面试的题目汇总可以加:936332305 / 链接:点击链接加入【安卓开发架构】:https://jq.qq.com/?_wv=1027&k=515xp64

现代主义是人文主义的高级发展阶段。翔宇剧社排的剧挺现代的。我有点跟不上现代主义的步伐。 跟一个人讲不符合他的认知水平的知识,会对他造成不必要的痛苦。在看民主的黄昏这篇文章时,隐约感受到一个太监听别人讲纵欲的后果的痛苦。 我能不能以我的接受能力去要求其他的人?以我的接受能力,...

文 / 杨大侠 1 每年7月到9月 非洲北部的马拉河畔 都挤满了15万之多的斑马 它们来自塞伦盖蒂,来自马赛马拉 来自安博塞利,来自无数个早已干涸的东非高原 它们走过4000公里的漫长旅程 躲过狮群昼伏夜出的猛烈攻击 现在,它们不得不趟入水深流急的马拉河 进行波澜壮阔的史诗...

北京时间客户端