关于android开发设置View Pager的直接跳转页set CurrentItem会阻塞主线程ANR。

根据网上解决的说法,分析源码:

if (mFirstLayout) {
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}

是因为主线程测量滑动距离,绘制UI阻塞,因此通过反射拿到 mFirstLayout变量,每次在setCurrentItem的代码之前设置为true,

try {

Field mFirstLayout = ViewPager.class
.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(vpImg, true);
vpImg.setCurrentItem(num + numCenter, false);
} catch (Exception e) {
e.printStackTrace();

}

根据以上解决方法本应能够解决ANR,可事实依然存在问题,上码:

@Override
public int getCount() {
tvPicSum.setText(vpImg.getCurrentItem() % mOrderListPic.size() +
1 + "/"
+ mOrderListPic.size());
if (mOrderListPic.size() >= 2) {// 当条目超过一个
return Integer.MAX_VALUE;
}
return mOrderListPic.size();
}

这是我的适配器PagerAdapter的getCount()方法,为了能够实现ViewPager的近似无限轮播效果,我们将viewPager的限制页数设置为Integer类型的最大值,但也从而会使ViewPager在setCurrentItem时测量页数太大,绘制UI频繁而阻塞主线程ANR,因此我将数量改成了相对较小些mOrderListPic.size()*40。问题便得带了根本的解决。

标签: Android轮播图
2016-12-21 22:21 1698人阅读 评论(1) 收藏 举报

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

目录(?)[+]

 

项目需求有无限轮播图,之前一直用的没问题,就用之前的放上去了,但是,有个需求是刷新时,把轮播图位置复位,心想不就是setCurrentItem么,so easy!

但....事情却没有那么简单

大家都知道,无限轮播图的做法就是把Adapter中重写getCount返回一个很大的数字,欺骗viewpager有很多,在对position和数据size取模,使数据的position和实际的position对应上,然后使用的时候把当前position设置到getCount数值 的中间,所以setAdapter后setCurrentItem(...),ok,到这里一切顺利

当页面刷新时,得到新数据,对viewpager重新设置数据,然后再次setCurrentItem恢复到初始位置时,问题就来了,这时整个页面完全卡死,过一会就ANR了

懵了......

这么简单的问题竟然会有问题

好了,开始解决问题

经过调试,问题代码就出现在setCurrentItem这行代码,查看ViewPager源码,发现最终调用到这个方法:

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {}

方法里面有行判断:

if (mFirstLayout) {
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}

mFirstLayout是一个私有变量,默认为true,第一次设置数据时,mFirstLayout为true,然后在viewpager的
onLayout方法中就被设置成了false
当下次再次setCurrentItem时就进入了else中,这时,else中的代码就会引起UI卡顿,具体原因还未深入研究
但到这就有了思路了,可以利用反射,强行修改mFirstLayout的值为true
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(vp_top, true);
myPagerAdapter.notifyDataSetChanged();
vp_top.setCurrentItem(Integer.MAX_VALUE/4-( Integer.MAX_VALUE/4 % ids_list_data.size() ));
}catch(Exception e) {
e.printStackTrace();
}

好了,到这里问题解决

ps 中间考虑过的方法还有一种,就是获取当前position,经过判断需要位移多受啊能到初始位置,就在刷新时偏移多少,但
是经测试,发现一个问题,在
vp_top.setCurrentItem(vp_top.getCurrentItem()+1);这样偏移一个单位时是没问题的,但是大于1就会卡顿,这个原因
不是很清楚,可能还是跟view的实例化有关,还需要深入研究

关于ViewPager设置属性页setCurrentItem会阻塞主线程ANR总结的更多相关文章

  1. Kafka producer异步发送在某些情况会阻塞主线程,使用时候慎重

    最近发现一个Kafka producer异步发送在某些情况会阻塞主线程,后来在排查解决问题过程中发现这可以算是Kafka的一个说明不恰当的地方. 问题说明 在很多场景下我们会使用异步方式来发送Kafk ...

  2. join为啥会阻塞主线程?

    join使用 上篇我们介绍了CountDownLatch,顺便说到了Thread中的join方法! import java.util.concurrent.TimeUnit; /** * @autho ...

  3. MFC编程入门之十三(对话框:属性页对话框及相关类的介绍)

    前面讲了模态对话框和非模态对话框,本节来将一种特殊的对话框--属性页对话框. 属性页对话框的分类 属性页对话框想必大家并不陌生,XP系统中桌面右键点属性,弹出的就是属性页对话框,它通过标签切换各个页面 ...

  4. VS2010/MFC编程入门之十三(对话框:属性页对话框及相关类的介绍)

    前面讲了模态对话框和非模态对话框,本节开始鸡啄米讲一种特殊的对话框--属性页对话框.另外,本套教程所讲大部分对VC++各个版本均可适用或者稍作修改即可,但考虑到终究还是基于VS2010版本的,所以将& ...

  5. VS2010-MFC(对话框:属性页对话框及相关类的介绍)

    转自:http://www.jizhuomi.com/software/164.html 一 属性页对话框的分类 属性页对话框想必大家并不陌生,XP系统中桌面右键点属性,弹出的就是属性页对话框,它通过 ...

  6. contextmap相当于session之类的 用于设置属性 投放到页面上 contextmap的数据存储在map中

    contextmap相当于session之类的 用于设置属性 投放到页面上

  7. Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面

    感觉 Android 到处都是坑,每个地方都要把人折腾半天. 今天来简单说说 Android之ActionBar.Tabs.Fragment.ViewPager 实现标签页切换并缓存页面 关于他们的介 ...

  8. 安卓TabLayout+ViewPager实现切页

    安卓使用TabLayout+ViewPager+Fragment 实现页面切换,可实现左右滑动切换视图界面和点击切换 可自定义菜单栏是在顶部还是在底部 一.实现效果: 二.实现过程: 2.1 一些重要 ...

  9. ViewPager之引导页

    一.概述 ViewPager是android-support-v4中提供的类,它是一个容器类,常用于页面之间的切换. 本文介绍ViewPager最基础的应用:在多个View之间进行切换,亦即ViewP ...

随机推荐

  1. powerdesigner 生成数据库脚本

    PowerDesigner导出所有SQL脚本 操作:Database=>Generate Database PowerDesigner怎么导出建表sql脚本 1 按照数据库类型,切换数据库. D ...

  2. 【转】使用 Android 的日志工具LogCat

    Android中的日志工具类是 Log(android.util.Log),这个类中提供了如下几个方法来供我们打印日志. 1.    Log.v() 这个方法用于打印那些最为琐碎的,意义最小的日志信息 ...

  3. ubuntu12.04 lts 安装gcc 4.8

    gcc 4.8.1 是第一个完全支持C++11 的编译器,Windows上可以安装mingw版的,在sourceforge 上有下载,安装也比较方便.在Linux上安装的话需要首先安装一些依赖库.在U ...

  4. SqlServer判断表、列不存在则创建

    一.表不存在则创建: if not exists (select * from sysobjects where id = object_id('mytab') and OBJECTPROPERTY( ...

  5. 使用devenv/MSBuild在命令行编译sln或csproj

    一 使用devenv来build单个project   devenv是VisualStudio的可执行程序,一般安装在“C:\Program Files (x86)\Microsoft Visual ...

  6. websocket与canvas[转]

    server端还是用tomcat7的方式客户端 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  ...

  7. MAVEN创建JAVA的Web工程

    maven命令:http://blog.csdn.net/edward0830ly/article/details/8748986 1.创建MAVEN的Web工程 mvn archetype:gene ...

  8. MySQL auto_increment初始值设置

    http://blog.csdn.net/u011439289/article/details/48055917 DROP TABLE IF EXISTS zan1; CREATE TABLE zan ...

  9. 一个封装的使用Apache HttpClient进行Http请求(GET、POST、PUT等)的类。

    一个封装的使用Apache HttpClient进行Http请求(GET.POST.PUT等)的类. import com.qunar.payment.gateway.front.channel.mp ...

  10. 通过 Apache Commons HttpClient 发送 HTTPS 请求

    1.通过 HTTPS 发送 POST 请求: 2.HTTPS 安全协议采用 TLSv1.2: 3. 使用代理(Proxy)进行 HTTPS 访问: 4.指定 Content-Type 为:applic ...